diff --git a/.babelrc b/.babelrc deleted file mode 100644 index cea726b87..000000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["es2015"], -} diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index b1c953d5a..000000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "notebook/static/components" -} \ No newline at end of file diff --git a/.github/workflows/enforce-labels.yml b/.github/workflows/enforce-labels.yml deleted file mode 100644 index 354a0468d..000000000 --- a/.github/workflows/enforce-labels.yml +++ /dev/null @@ -1,11 +0,0 @@ -name: Enforce PR label - -on: - pull_request: - types: [labeled, unlabeled, opened, edited, synchronize] -jobs: - enforce-label: - runs-on: ubuntu-latest - steps: - - name: enforce-triage-label - uses: jupyterlab/maintainer-tools/.github/actions/enforce-label@v1 diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml deleted file mode 100644 index 9ce5424e2..000000000 --- a/.github/workflows/js.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Linux JS Tests - -on: - push: - branches: '*' - pull_request: - branches: '*' - -jobs: - build: - runs-on: ${{ matrix.os }}-latest - strategy: - fail-fast: false - matrix: - os: [ubuntu, macos] - group: [notebook, base, services] - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - - name: Cache node modules - uses: actions/cache@v2 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - - name: Cache pip on Linux - uses: actions/cache@v1 - if: startsWith(runner.os, 'Linux') - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ matrix.python }}-${{ hashFiles('**/requirements.txt', 'setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python }} - - - name: Install dependencies - run: | - pip install --upgrade pip - pip install --upgrade setuptools wheel - npm install - npm install -g casperjs@1.1.3 phantomjs-prebuilt@2.1.7 - pip install .[test] - - - name: Run Tests - run: | - python -m notebook.jstest ${{ matrix.group }} diff --git a/.github/workflows/python-nbconvert.yml b/.github/workflows/python-nbconvert.yml deleted file mode 100644 index d7dfd07c1..000000000 --- a/.github/workflows/python-nbconvert.yml +++ /dev/null @@ -1,53 +0,0 @@ -# The NBConvert Service requires pandoc. Instead of testing -# Pandoc on every operating system (which should already be -# done in nbconvert directly), we'll only test these services -# on ubuntu where we can easily load Pandoc from a Github -# Actions docker image (this docker image is not on other -# operating systems). -name: NBConvert Service Tests -on: - push: - branches: '*' - pull_request: - branches: '*' -jobs: - build: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: [ '3.7', '3.8', '3.9', '3.10' ] - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Install Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - architecture: 'x64' - - name: Setup Pandoc - uses: r-lib/actions/setup-pandoc@v1 - - name: Upgrade packaging dependencies - run: | - pip install --upgrade pip setuptools wheel - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - name: Cache pip - uses: actions/cache@v1 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python-version }}- - ${{ runner.os }}-pip- - - name: Install the Python dependencies - run: | - pip install -e .[test] - - name: Run NBConvert Tests - run: | - pytest notebook/nbconvert/tests/ - - name: Run NBConvert Service Tests - run: | - pytest notebook/services/nbconvert/tests/ diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml deleted file mode 100644 index 282ea1fd8..000000000 --- a/.github/workflows/python.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Python Tests -on: - push: - branches: '*' - pull_request: - branches: '*' -jobs: - build: - runs-on: ${{ matrix.os }}-latest - strategy: - fail-fast: false - matrix: - os: [ubuntu, macos, windows] - python-version: [ '3.7', '3.8', '3.9', '3.10' ] - steps: - - name: Checkout - uses: actions/checkout@v1 - - name: Install Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - architecture: 'x64' - - name: Upgrade packaging dependencies - run: | - pip install --upgrade pip setuptools wheel --user - - name: Get pip cache dir - id: pip-cache - run: | - echo "::set-output name=dir::$(pip cache dir)" - - name: Cache pip - uses: actions/cache@v1 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip-${{ matrix.python-version }}-${{ hashFiles('setup.py') }} - restore-keys: | - ${{ runner.os }}-pip-${{ matrix.python-version }}- - ${{ runner.os }}-pip- - - name: Install the Python dependencies - run: | - pip install -e .[test] codecov - - name: List installed packages - run: | - pip freeze - pip check - - name: Run Server-side tests - run: | - pytest -vv --cov notebook --cov-branch --cov-report term-missing:skip-covered --ignore-glob=notebook/tests/selenium/* --ignore-glob=notebook/nbconvert/tests/* --ignore-glob=notebook/services/nbconvert/tests/* - - name: Run Integration Tests - run: | - pytest -v notebook/tests/test_notebookapp_integration.py --integration_tests - - name: Coverage - run: | - codecov diff --git a/.github/workflows/selenium.yml b/.github/workflows/selenium.yml deleted file mode 100644 index b0c470eb8..000000000 --- a/.github/workflows/selenium.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Selenium Tests - -on: - push: - branches: '*' - pull_request: - branches: '*' -jobs: - build: - runs-on: ${{ matrix.os }}-latest - strategy: - fail-fast: false - matrix: - os: [ubuntu, macos] - python-version: [ '3.7', '3.8', '3.9', '3.10' ] - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - architecture: 'x64' - - - name: Set up Node - uses: actions/setup-node@v1 - with: - node-version: '12.x' - - - name: Install JS - run: | - npm install - - - name: Install Python dependencies - run: | - python -m pip install -U pip setuptools wheel - pip install --upgrade selenium - pip install pytest - pip install .[test] - - - name: Run Tests - run: | - export JUPYTER_TEST_BROWSER=firefox - export MOZ_HEADLESS=1 - pytest -sv notebook/tests/selenium diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 diff --git a/.mailmap b/.mailmap deleted file mode 100644 index bd6544e25..000000000 --- a/.mailmap +++ /dev/null @@ -1,149 +0,0 @@ -A. J. Holyoake ajholyoake -Aaron Culich Aaron Culich -Aron Ahmadia ahmadia -Benjamin Ragan-Kelley -Benjamin Ragan-Kelley Min RK -Benjamin Ragan-Kelley MinRK -Barry Wark Barry Wark -Ben Edwards Ben Edwards -Bradley M. Froehle Bradley M. Froehle -Bradley M. Froehle Bradley Froehle -Brandon Parsons Brandon Parsons -Brian E. Granger Brian Granger -Brian E. Granger Brian Granger <> -Brian E. Granger bgranger <> -Brian E. Granger bgranger -Christoph Gohlke cgohlke -Cyrille Rossant rossant -Damián Avila damianavila -Damián Avila damianavila -Damon Allen damontallen -Darren Dale darren.dale <> -Darren Dale Darren Dale <> -Dav Clark Dav Clark <> -Dav Clark Dav Clark -David Hirschfeld dhirschfeld -David P. Sanders David P. Sanders -David Warde-Farley David Warde-Farley <> -Doug Blank Doug Blank -Eugene Van den Bulke Eugene Van den Bulke -Evan Patterson -Evan Patterson -Evan Patterson -Evan Patterson -Evan Patterson epatters -Evan Patterson epatters -Ernie French Ernie French -Ernie French ernie french -Ernie French ernop -Fernando Perez -Fernando Perez Fernando Perez -Fernando Perez fperez <> -Fernando Perez fptest <> -Fernando Perez fptest1 <> -Fernando Perez Fernando Perez -Fernando Perez Fernando Perez <> -Fernando Perez Fernando Perez -Frank Murphy Frank Murphy -Gabriel Becker gmbecker -Gael Varoquaux gael.varoquaux <> -Gael Varoquaux gvaroquaux -Gael Varoquaux Gael Varoquaux <> -Ingolf Becker watercrossing -Jake Vanderplas Jake Vanderplas -Jakob Gager jakobgager -Jakob Gager jakobgager -Jakob Gager jakobgager -Jason Grout -Jason Grout -Jason Gors jason gors -Jason Gors jgors -Jens Hedegaard Nielsen Jens Hedegaard Nielsen -Jens Hedegaard Nielsen Jens H Nielsen -Jens Hedegaard Nielsen Jens H. Nielsen -Jez Ng Jez Ng -Jonathan Frederic Jonathan Frederic -Jonathan Frederic Jonathan Frederic -Jonathan Frederic Jonathan Frederic -Jonathan Frederic jon -Jonathan Frederic U-Jon-PC\Jon -Jonathan March Jonathan March -Jonathan March jdmarch -Jörgen Stenarson Jörgen Stenarson -Jörgen Stenarson Jorgen Stenarson -Jörgen Stenarson Jorgen Stenarson <> -Jörgen Stenarson jstenar -Jörgen Stenarson jstenar <> -Jörgen Stenarson Jörgen Stenarson -Juergen Hasch juhasch -Juergen Hasch juhasch -Julia Evans Julia Evans -Kester Tong KesterTong -Kyle Kelley Kyle Kelley -Kyle Kelley rgbkrk -Laurent Dufréchou -Laurent Dufréchou -Laurent Dufréchou laurent dufrechou <> -Laurent Dufréchou laurent.dufrechou <> -Laurent Dufréchou Laurent Dufrechou <> -Laurent Dufréchou laurent.dufrechou@gmail.com <> -Laurent Dufréchou ldufrechou -Lorena Pantano Lorena -Luis Pedro Coelho Luis Pedro Coelho -Marc Molla marcmolla -Martín Gaitán Martín Gaitán -Matthias Bussonnier Matthias BUSSONNIER -Matthias Bussonnier Bussonnier Matthias -Matthias Bussonnier Matthias BUSSONNIER -Matthias Bussonnier Matthias Bussonnier -Michael Droettboom Michael Droettboom -Nicholas Bollweg Nicholas Bollweg (Nick) -Nicolas Rougier -Nikolay Koldunov Nikolay Koldunov -Omar Andrés Zapata Mesa Omar Andres Zapata Mesa -Omar Andrés Zapata Mesa Omar Andres Zapata Mesa -Pankaj Pandey Pankaj Pandey -Pascal Schetelat pascal-schetelat -Paul Ivanov Paul Ivanov -Pauli Virtanen Pauli Virtanen <> -Pauli Virtanen Pauli Virtanen -Pierre Gerold Pierre Gerold -Pietro Berkes Pietro Berkes -Piti Ongmongkolkul piti118 -Prabhu Ramachandran Prabhu Ramachandran <> -Puneeth Chaganti Puneeth Chaganti -Robert Kern rkern <> -Robert Kern Robert Kern -Robert Kern Robert Kern -Robert Kern Robert Kern <> -Robert Marchman Robert Marchman -Satrajit Ghosh Satrajit Ghosh -Satrajit Ghosh Satrajit Ghosh -Scott Sanderson Scott Sanderson -smithj1 smithj1 -smithj1 smithj1 -Steven Johnson stevenJohnson -Steven Silvester blink1073 -S. Weber s8weber -Stefan van der Walt Stefan van der Walt -Silvia Vinyes Silvia -Silvia Vinyes silviav12 -Sylvain Corlay -Sylvain Corlay sylvain.corlay -Ted Drain TD22057 -Théophile Studer Théophile Studer -Thomas Kluyver Thomas -Thomas Spura Thomas Spura -Timo Paulssen timo -vds vds2212 -vds vds -Ville M. Vainio -Ville M. Vainio ville -Ville M. Vainio ville -Ville M. Vainio vivainio <> -Ville M. Vainio Ville M. Vainio -Ville M. Vainio Ville M. Vainio -Walter Doerwald walter.doerwald <> -Walter Doerwald Walter Doerwald <> -W. Trevor King W. Trevor King -Yoval P. y-p diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index 6f947cb58..000000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,197 +0,0 @@ -Contributing to the Jupyter Notebook -==================================== - -If you're reading this section, you're probably interested in contributing to -Jupyter. Welcome and thanks for your interest in contributing! - -Please take a look at the Contributor documentation, familiarize yourself with -using the Jupyter Notebook, and introduce yourself on the mailing list and -share what area of the project you are interested in working on. - -General Guidelines ------------------- - -For general documentation about contributing to Jupyter projects, see the -`Project Jupyter Contributor Documentation`__. - -__ https://jupyter.readthedocs.io/en/latest/contributing/content-contributor.html - - -Setting Up a Development Environment ------------------------------------- - -Installing Node.js and npm -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Building the Notebook from its GitHub source code requires some tools to -create and minify JavaScript components and the CSS, -specifically Node.js and Node's package manager, ``npm``. -It should be node version ≥ 6.0. - -If you use ``conda``, you can get them with:: - - conda install -c conda-forge nodejs - -If you use `Homebrew `_ on Mac OS X:: - - brew install node - -Installation on Linux may vary, but be aware that the `nodejs` or `npm` packages -included in the system package repository may be too old to work properly. - -You can also use the installer from the `Node.js website `_. - - -Installing the Jupyter Notebook -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Once you have installed the dependencies mentioned above, use the following -steps:: - - pip install --upgrade setuptools pip - git clone https://github.com/jupyter/notebook - cd notebook - pip install -e . - -If you are using a system-wide Python installation and you only want to install the notebook for you, -you can add ``--user`` to the install commands. - -Once you have done this, you can launch the master branch of Jupyter notebook -from any directory in your system with:: - - jupyter notebook - -Verification -^^^^^^^^^^^^ - -While running the notebook, select one of your notebook files (the file will have the extension ``.ipynb``). -In the top tab you will click on "Help" and then click on "About". In the pop window you will see information about the version of Jupyter that you are running. You will see "The version of the notebook server is:". -If you are working in development mode, you will see that your version of Jupyter notebook will include the word "dev". If it does not include the word "dev", you are currently not working in development mode and should follow the steps below to uninstall and reinstall Jupyter. - -Troubleshooting the Installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you do not see that your Jupyter Notebook is not running on dev mode, it's possible that you are -running other instances of Jupyter Notebook. You can try the following steps: - -1. Uninstall all instances of the notebook package. These include any installations you made using - pip or conda. -2. Run ``python3 -m pip install -e .`` in the notebook repository to install the notebook from there. -3. Run ``npm run build`` to make sure the Javascript and CSS are updated and compiled. -4. Launch with ``python3 -m notebook --port 8989``, and check that the browser is pointing to ``localhost:8989`` - (rather than the default 8888). You don't necessarily have to launch with port 8989, as long as you use - a port that is neither the default nor in use, then it should be fine. -5. Verify the installation with the steps in the previous section. - - -Rebuilding JavaScript and CSS -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -There is a build step for the JavaScript and CSS in the notebook. -To make sure that you are working with up-to-date code, you will need to run -this command whenever there are changes to JavaScript or LESS sources:: - - npm run build - -**IMPORTANT:** Don't forget to run ``npm run build`` after switching branches. -When switching between branches of different versions (e.g. ``4.x`` and -``master``), run ``pip install -e .``. If you have tried the above and still -find that the notebook is not reflecting the current source code, try cleaning -the repo with ``git clean -xfd`` and reinstalling with ``pip install -e .``. - -Development Tip -""""""""""""""" - -When doing development, you can use this command to automatically rebuild -JavaScript and LESS sources as they are modified:: - - npm run build:watch - -Git Hooks -""""""""" - -If you want to automatically update dependencies and recompile JavaScript and -CSS after checking out a new commit, you can install post-checkout and -post-merge hooks which will do it for you:: - - git-hooks/install-hooks.sh - -See ``git-hooks/README.md`` for more details. - - -Running Tests -------------- - -Python Tests -^^^^^^^^^^^^ - -Install dependencies:: - - pip install -e '.[test]' - -To run the Python tests, use:: - - pytest - -If you want coverage statistics as well, you can run:: - - py.test --cov notebook -v --pyargs notebook - -JavaScript Tests -^^^^^^^^^^^^^^^^ - -To run the JavaScript tests, you will need to have PhantomJS and CasperJS -installed:: - - npm install -g casperjs phantomjs-prebuilt - -Then, to run the JavaScript tests:: - - python -m notebook.jstest [group] - -where ``[group]`` is an optional argument that is a path relative to -``notebook/tests/``. -For example, to run all tests in ``notebook/tests/notebook``:: - - python -m notebook.jstest notebook - -or to run just ``notebook/tests/notebook/deletecell.js``:: - - python -m notebook.jstest notebook/deletecell.js - - -Building the Documentation --------------------------- - -To build the documentation you'll need `Sphinx `_, -`pandoc `_ and a few other packages. - -To install (and activate) a conda environment named ``notebook_docs`` -containing all the necessary packages (except pandoc), use:: - - conda create -n notebook_docs pip - conda activate notebook_docs # Linux and OS X - activate notebook_docs # Windows - pip install .[docs] - -If you want to install the necessary packages with ``pip``, use the following instead:: - - pip install .[docs] - -Once you have installed the required packages, you can build the docs with:: - - cd docs - make html - -After that, the generated HTML files will be available at -``build/html/index.html``. You may view the docs in your browser. - -You can automatically check if all hyperlinks are still valid:: - - make linkcheck - -Windows users can find ``make.bat`` in the ``docs`` folder. - -You should also have a look at the `Project Jupyter Documentation Guide`__. - -__ https://jupyter.readthedocs.io/en/latest/contributing/docs-contributions/index.html diff --git a/binder/example.ipynb b/binder/example.ipynb deleted file mode 100644 index 51a2c3208..000000000 --- a/binder/example.ipynb +++ /dev/null @@ -1,339 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Welcome to RetroLab! 👋\n", - "\n", - "**RetroLab is an alternative distribution of JupyterLab**. It is built using the same components as in JupyterLab, and reuse a lot of the work from the JupyterLab community by leveraging the new federated (prebuilt) extension system.\n", - "\n", - "The goal of RetroLab is to provide an interface focused on the notebook for users that would like a leaner and simpler interface with a **modern look and old school touch to it**.\n", - "\n", - "It is supposed to complement JupyterLab and its single document mode, not to replace it! All these different interfaces can perfectly be installed together in the same environment:\n", - "\n", - "- JupyterLab (`jupyterlab` package)\n", - "- NBClassic (`nbclassic` package): provides the Classic Notebook interface formely developed in https://github.com/jupyter/notebook\n", - "- RetroLab (`retrolab` package): the interface you are probably currently using if looking at this notebook :)" - ] - }, - { - "attachments": { - "2d33971b-509e-433b-809e-2f0861a13105.png": { - "image/png": "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" - }, - "5aa6b072-c4d7-47de-9e75-0a107a37e2f2.png": { - "image/png": "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" - }, - "c448a783-da5a-499b-a52d-62be28a72438.png": { - "image/png": "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" - }, - "d183cf17-977b-4c28-b892-123bde959d5b.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Files 📂 and Running Sessions 🏃‍♀️\n", - "\n", - "Just like in the classic notebook, RetroLab lets you navigate the files in a separate browser tab. \n", - "\n", - "Go ahead and click on the Jupyter icon in the top left corner!\n", - "\n", - "![image.png](attachment:d183cf17-977b-4c28-b892-123bde959d5b.png)\n", - "\n", - "It will open a new browser tab with the listing of the files on the server:\n", - "\n", - "![image.png](attachment:5aa6b072-c4d7-47de-9e75-0a107a37e2f2.png)\n", - "\n", - "It also shows the list of running sessions and terminals in the `Running` tab:\n", - "\n", - "![image.png](attachment:c448a783-da5a-499b-a52d-62be28a72438.png)\n", - "\n", - "Alternatively it is also possible to access this page using the command in the `View` menu:\n", - "\n", - "![image.png](attachment:2d33971b-509e-433b-809e-2f0861a13105.png)" - ] - }, - { - "attachments": { - "72f98bea-d61c-40cd-8f56-29df50ae5f8d.png": { - "image/png": "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" - }, - "86ac8b15-8a6b-4d4d-b315-0c8a73870e3b.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Editing Files 🖊️\n", - "\n", - "RetroLab also has support for editing files. Double-click on a file (or `Right Click > Open`) to open the editor:\n", - "\n", - "![image.png](attachment:72f98bea-d61c-40cd-8f56-29df50ae5f8d.png)\n", - "\n", - "![image.png](attachment:86ac8b15-8a6b-4d4d-b315-0c8a73870e3b.png)" - ] - }, - { - "attachments": { - "23b23672-e7ae-44f0-9588-63208bcf0caf.png": { - "image/png": "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" - }, - "9016e117-00db-490f-80c4-fa3ed6766d0f.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Terminals 🖥️\n", - "\n", - "To create a new Terminal, select `File > New > Terminal` in the menu:\n", - "\n", - "![image.png](attachment:9016e117-00db-490f-80c4-fa3ed6766d0f.png)\n", - "\n", - "The terminal opens in a new browser tab:\n", - "\n", - "![image.png](attachment:23b23672-e7ae-44f0-9588-63208bcf0caf.png)" - ] - }, - { - "attachments": { - "72198f40-0581-4a18-bc23-8b4674351a97.png": { - "image/png": "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8WnDtOz0vaw17i9bbRavMjLOzDt1b9ZuOrdi6tOcxTX7nveNqWFXuU8LyXnO4nK+sXYlXXwe+RuKDkAABEAABEAABEAABEBAFlTOcqjEYKQwUnU8RB5fDiON/DF/egfSSDtfD/PTb4c7gAAIgAAIgAAIgAAIgECUBM4ipD3fRwEjhZFGOTAH7g0jHUAy/ASMdDgXnAUBEAABEAABEAABELiUBGCkg2/LmZg8fPjwyZMnz549e/HixcuXL1+9evX69es3b968ffv23cDxzXscf/fNN98MXPju7du3b968ef369atXr16+fPnixYtnz549efLk4cOHgw/wUZ6Bkb7n2wojfU9QaAYCIAACIAACIAACIHAZCJzJvtSEUSNFjVQdD5HHMNLIEaMDEAABEAABEAABEAABEBg5ARjpIPIzMUGNdBBgJGdgpJFgxU1BAARAAARAAARAAARA4EIJnMm+1ExRI0WNVB0Pkccw0sgRowMQAAEQAAEQAAEQAAEQGDkBGOkg8jMxQY10EGAkZ2CkkWDFTUEABEAABEAABEAABEDgQgmcyb7UTFEjRY1UHQ+RxzDSyBGjAxAAARAAARAAARAAARAYOQEY6SDyMzFBjXQQYCRnYKSRYMVNQQAEQAAEQAAEQAAEQOBCCZzJvtRMUSNFjVQdD5HHMNLIEaMDEAABEAABEAABEAABEBg5gQ820t/97ndffvnl119//c0333z77bd//vOfv//+e9d1/zc4fjjvY2RszsQENdIRvS8w0hGBRjcgAAIgAAIgAAIgAAIgMEICZ7IvNa+///u//8d//Md/+qd/+pd/+Zdf/OIXv/zlLzc3N/9VOf7PeR9q75HGZ2ICI430vejeHEbaZYEIBEAABEAABEAABEAABD4WAmeyL/Whb9269Q//8A93797953/+542NjV/84hf379//pXIUz/tQe480PhMTGGmk70X35jDSLgtEIAACIAACIAACIAACIPCxEDiTfakP/etf/3p3d/fRo0dPnz7d39+v1+sHBwd/+MMfvgyO5yccX33oofYeaXwmJjDSSN+L7s1hpF0WiEAABEAABEAABEAABEDgYyFwJvtSH3pnZ+e3v/3tF1988fz588PDwz/+8Y9ff/31q1evXgdH84TjzYceau+RxmdiAiON9L3o3hxG2mWBCARAAARAAARAAARAAAQ+FgJn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qVRIZQLuborFU5Xj0/bale387yOdkN9HShO6dbNYC5aANh9krRnOpzif0pN3qv5pZydjTlKa4LqVyd/Q6PWy11l7r12WYHzOzntPIc/jAAEQAAEQAAEQAAEQAIGTCXywkf7617/e3d199OjR06dP9/f36/X6wcHBH/7why+Dw3fUjqb6FdSjoyN/Zq/65aVqmRRGCiMdPlovh5EOz+0nnu2UUn/ifXA5CIAACIAACIAACIAACPzsCHywkf7Xf/3X/v5+o9F4/fr127dv//SnPzmO8+23334XHMfK8Wfv+Mtf/vL27du+r4rp230XRgojHf4/EYx0OBecBQEQAAEQAAEQAAEQAIGfM4EPNtJardZoNN6+ffvdd999//33P/zww48//vjXv/61Iw5Dqbx7967RaKhSetK3lQ6q6dAbRnHyTEywjjSKt2DIPTsD669//euPP/74ww8/fP/99999993bt28bjUatVhtyzc/kFGqkP5M3CmmCAAiAAAiAAAiAAAicP4Ez2Zfa/YcZabPZ/PLLLw8PD7/++uvXr1935u6qE3f9GEbawwTfR/oRG6n6/xViEAABEAABEAABEAABEPibIjBiI/3666+/+OKLFy9edMqknS2OegTs3TsYaQ8QGCmM9G/qLyY8LAiAAAiAAAiAAAiAwN8IgREb6cuXL//nf/7n+fPnL1++9MukMNI+98Y60uH/68FIh3PBWRAAARAAARAAARAAARD4ORMYsZE2Go3f//73BwcHh4eHR0dHr1+/hpHCSN/rfyAY6XthQiMQAAEQAAEQAAEQAAEQ+FkR+GAj3djY+NWvflUul3d2dh4+fPib3/zmv7zjv4OjOuzY29t78uRJvV5vNBow0j4X9X9FjXT4/0Aw0uFccBYEQAAEQAAEQAAEQAAEfs4EPthId3Z2fve7333xxRdfffXVy5cvG41G5ytJ/+AdwfeSdn9+9dVXv//97x8/fvzs2TN/x91Xr16dtLnRoK2NDPOZmGCv3RG9LzDSEYFGNyAAAiAAAiAAAiAAAiAwQgJnsi81r8ePH3/55ZevXr3605/+9N1333377bcdtzzlC1329/d9j/U3N4KRDoo3aqTqMOvGMNIuC0QgAAIgAAIgAAIgAAIg8LEQ+GAj7fv2lz//+c/ffPPNn/70p/8bHEPv/MUXX8BIBy1UPQMjHf7/Fox0OBec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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Command Palette 🎨\n", - "\n", - "RetroLab includes a command palette, just like in JupyterLab.\n", - "\n", - "Hit `Ctrl-Shift-C` or `Accel-Shift-C` to activate it. Or via the menu with `View > Activate Command Palette`:\n", - "\n", - "![image.png](attachment:72198f40-0581-4a18-bc23-8b4674351a97.png)\n", - "\n", - "Using the palette is very convenient and can give a significant productivity boost over time!" - ] - }, - { - "attachments": { - "52cfe8f1-5d7f-4e99-8f43-95a16a8601bb.png": { - "image/png": "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" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Themes 🌈\n", - "\n", - "Since RetroLab is heavily built on top of JupyterLab, it also has support for a Dark Mode! 🕶️\n", - "\n", - "Go to `Settings > JupyterLab Theme > JupyterLab Dark` to select the theme:\n", - "\n", - "![image.png](attachment:52cfe8f1-5d7f-4e99-8f43-95a16a8601bb.png)\n", - "\n", - "\n", - "New themes can be installed using the federated extension system. These themes will be compatible with both JupyterLab and RetroLab." - ] - }, - { - "attachments": { - "ac1323eb-c6e0-4b7c-80f3-7bf5f84adf98.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAACVMAAAWbCAIAAAC4HiGsAAAgAElEQVR4Aezdb1xUdf7//+/FvfC50IXvBS98L3zns5aS0KQSSiiESGFRrZmZfyon65cLqd82WNuNILQ/uPl1WxTckj5lFn3IX0pWlqigoeKqgKBggcIM8tfBIYSTtK3O9yZHzh7nHzMwM+ff49y85Zkz73n/uZ+50Os8PWf+h4MNAQQQQAABh+MyGwIIIIAAAggggAACCCCAAAIyAWplBBBAAAEEENCiwP/Q4qSZMwIIIIBAEAVkZR27CCCAAAIIIIAAAggggAACCNwiEMTyk64QQAABBBBAIAwCJH9hQGYIBBBAQKUCtxRzvEAAAQQQQAABBBBAAAEEEEDAi4BKy1qmhQACCCCAAAJuAiR/biQcQAABBIwh4KWau+VwLxsCCCCAAAIIIIAAAggggIABBG4pBb28MEatzCoRQAABBBDQvADJn+ZPIQtAAAEExiDgpY67edhjVWtnQwABBBBAAAEEEEAAAQQQ0JGAx9LPd7U4hvKTjyCAAAIIIIBAmAVI/sIMznAIIICAKgQ81nLyqs+9mL3EhgACCCCAAAIIIIAAAgggoCMB97pPXhV6LBtVUdAyCQQQQAABBBDwKUDy55OHNxFAAAE9Cnis36QCT6r9XOrZHjYEEEAAAQQQQAABBBBAAAEdCbgUfVIxKJWHHotHPVbJrAkBBBBAAAFdCZD86ep0shgEEEDAHwH34k2q68RKTyz/pHq2223rYkMAAQQQQAABBBBAAAEEENCggFt51y2VfmIlKFaFUpHoXj/6U3XSBgEEEEAAAQQUFCD5UxCfoRFAAAEFBNzLNrGik2d+3d3dXV1dncNbx/DWzoYAAggggAACCCCAAAIIIKA7AbHiE6u/rq6u7u5u9/zPvYpUoJRlSAQQQAABBBDwW4Dkz28qGiKAAAK6EHCp2aR/yGm328V/6SlmfvLA7+Lw1saGAAIIIIAAAggggAACCCCgIwGx1hPTTCkC7OrqEmtDu90uFYwuhaQuimMWgQACCCCAgG4FSP50e2pZGAIIIOBRwKVgk274c4n9Ll68aLPZrFZra2try/B2QbadZ0MAAQQQQAABBBBAAAEEENCggKywuyDWeq2trVar1WazXbx4saOjo7Oz0z38cykkPRabHEQAAQQQQAABlQiQ/KnkRDANBBBAIEwCLgVbb2+v3W6/dOlST0+PeLffxYsXnWwIIIAAAggggAACCCCAAAKGFLh48aIU/l26dEm888+lkAxT+cowCCCAAAIIIDAmAZK/MbHxIQQQQEBrAi51mvhSvOHPJfazWq2GLG9ZNAIIIIAAAggggAACCCCAgNNqtbqEf2Ll6LGo1FplzHwRQAABBBAwhADJnyFOM4tEAAEEPBZpLjf8tbe3W63W5uZmil0EEEAAAQQQQAABBBBAAAFjCjQ3N1ut1vb2dvGZn95u+xNrTGptBBBAAAEEEFChAMmfCk8KU0IAAQSCL+Aj+ROf89nR0dHW1nb+/PnGxkZj1resGgEEEEAAAQQQQAABBBBAoLGx8fz5821tbR0dHWL45/GBnyR/wa/b6REBBBBAAIEgCZD8BQmSbhBAAAF1C7gnfy6P+uzo6LBarT/++GN9fT21LgIIIIAAAggggAACCCCAgDEF6uvrf/zxR6vVKiV/ly5d8vbAT3XXwcwOAQQQQAABgwqQ/Bn0xLNsBBAwmsCoyd/FixdbW1sbGxtramqMWd+yagQQQAABBBBAAAEEEEAAgZqamsbGxtbW1osXL0oP/CT5M9o1BNaLAAIIIKBpAZI/TZ8+Jo8AAgj4K+A7+evo6Lh48aL4qM+TJ09S6yKAAAIIIIAAAggggAACCBhT4OTJk+IDPy9evNjR0dHT08M9f/4W3rRDAAEEEEBAHQIkf+o4D8wCAQQQCLHAqMmf+CN/DQ0Nx48fN2Z9q/JVV1ZWpg9vlZWVKp8q00MgKAJ2uz0nJ6e6ujoovdEJAggggAACCCCAgM1mKysrKxreysrKbDabR5Pjx483NDRIP/VH8hfiYp3uEUAAAQQQCL4AyV/wTekRAQQQUKGAx+TPbrf39PR0d3d3dHS0tbU1NzefPXtWr8mfzWYrHt681bcei95RD547dy49Pd3iaSstLR31474bVFdXbxjZ0tPT84a39PT0kWMbCEV8A/Ku+gWqq6sFQRDn+cu5g8KhrcKhrVdPf3ntar/dbk9LS+NLrv6TyAwRQAABBBBAQP0CgiAUFRVZLJaMjAyxrMjIyLBYLEVFRdL/jEmrOH78+NmzZ5ubm9va2jo6Orq7u3t6eux2e29vr3tdqcLilykhgAACCCCAAMkf3wEEEEDAEALuFVpvb688+bPZbE1NTWfOnPEn+ROLRk9plyUnJ8e9dJRqSKV2bDabxWLJHt4sFotL+CcIQk5OjsViyc/PD3SGpaWl2dnZ5zxtdrs90N5c2svnbLFYxMBPZJfW4vIRg7y02+0/DG9yZBV+8WSn42rLrleXJEZM+I/f/OY/bjPNfOzV4sarsrd97ZatmHD3qzW/+mqi3ffS0tJsNtsv5w468lN6190l/bn8lzjh0FbtrouZI4AAAggggAAC6hEQ6x33f1NVXV2dlpbmXsEdP378zJkzTU1NNpuN5M8Q1wtYJAIIIICA7gRI/nR3SlkQAggg4EkguMmfxWLZt2+fe9olhlLupeOYi17xLr0xf1z6YHFxcXZ2tvgyOzu7uLhYekuK/bKzs8cQHZWWlubl5TmdTpvNVuplk6dT0rj+7FgsFhHZPWSVjvvTj482lZWVY1i1jw5D/ZYgCPn5+XKQ/Px88Z8wnzt3LtSjj7n/xsIHJ0yIfbm4puuq03m1q6b45TkTJjz4fotfHeo6+XM6nVdPl17eENdfskY4VPjP1hP/bD3x8/EdA6VZjr+lDHz5ml9ENEIAAQQQQAABBMIm0LAx9XbT5JHNPHvBmsKjl7yO3lb++c13j74en/x2sB5j3n/0vTULZpvNZnP8Iyu3VHoff3hiRUVFaWlpHv+3XxCEtLS0oqIi+QpI/jyV1BxDAAEEEEBASwIkf1o6W8wVAQQQGLOA/8lfVVWVvOrzuC8mUu5vSXlMTk6O+7tjOCI+iGYMH3T5SHFxsTQlefI3ztjP6XRKyV/G8CZOWP7fjIyMMdxKKM5fdLbZbPIOxX2bzXbu3DmLxeKy0kBf5uXlZWZmBj0zk74JLjuBTs+lvSAI6enpGRkZ1dXVYp5aXV0tPqfI23fSpQePL8XfO5G/5X5E/m7A+31fLJkw4bHiLvkH+yo//bRy+MhATdHzcyImRkRMjohITv/03PCtgF3fvJocYZo4NTZxyca3lozc89dXU7gidrLJNDkiYuaSjVV98g41un/tar9wqPDa1X6P8796uvSXcwc9vsVBBBBAAAEEEEBAGYGGjamRK0sHbw7e31CyJtH87GdesreLHy9NebN6+OENQUz++r9cEzN3bWnrkNM51Pb5ypiYNd+OzMfdRHz8iY8nqFdXV1ssFvm/VqyqquKevzGX3nwQAQQQQAABNQiQ/KnhLDAHBBBAIOQCvpO/9vZ28Wmf9fX1QUn+xp9IiSWrmHK5l6+BHhHL3ZzhzWK5+UjS8cd+8uTPYrF4/GE/KRoMdM5Op9N3mhWs5E8M58Q758YwSY8fcQn8pJceG/t/MD8/PyMjw+VfK0vPnh1zfilKygXcj/g/SQ8ty9NN/3PJFwMe3nE6rx7LjJjw8JaWG3nf1Zq3Ym+b+Uaj8+o3z5tMT31xIxi82rjl4Qm/ibzxtM+re9NN//uxouYbTfv2rIj43yu+8dynx4GCcLC0tNQFXxAEj197/wfzlvlJPYzaQGrJDgIIIIAAAgggEA6BW5M/p9N59i/J5vTSmk3JMemlI/+aaejbP8Qkv/Fe9lzz5Mnm+IdWlrQ6byR/r3+8bc2C5Nkx5sSlGyvFtv3VH6xZMDc+OSU5+ZFnNx4YThAvfrw0Zs22z7JXPrd0wdz41D+UNN/64Pf+hm+/rRnJGvtLV5oXbGv1uvR9+/ZlZGR4fXv4jYyMjH379kltqqqq6uvrxad9tre38zt/IS/XGQABBBBAAIFgC5D8BVuU/hBAAAFVCgQ9+ZOyHG87Ut04np1gJX/i0zjFZ4dmZ2eL4Z/dbhd/Lc8lzAhowlKwp/Xkz2KxpKenHzlyJKDle2scim+F3W63WCwu/1pZiv18p6Te5ikeF3M+UUDs3/2I7x58v3t115LbJr587NbrNTc/8mvNq5G3Lfl85Cf/Lm6Zc9ucLa3HbhzcdfNg38eP3Tac/B38/QTTqpEb4G58cMKKvb5HDua74pOg5M/ylbLzMWeuwZwffSGAAAIIIIAAAuERcEv+qt9ONq/5duj8lgXTny3pHJ5E/7drYlK3/OB0VmbHz/33PX/mxDUl52/cqHc2f8HkJdvanM7+A2vjE9d8O/yp/mNvpoo9dH68dLL52Y+ah5xO5+DR7MSYtRVe1jZ06Wjh0viFW856/F/N4Q8VFRWJP0/gpYsbh/Py8uQ/iEDyp8qankkhgAACCCAQgADJXwBYNEUAAQS0K6Ch5K+4uHjDyJY+vI282iAvR30Urr7fEgQhOzs7LS0tLy/PbrePJ/bT0z1/Ula3YcMG+aN+fGN6e1fqzWXHW3t/jotp3DjPl8eBpJxPnG1xcbH4yCNp8sXFxeMatzzddJuXe/5+PZj+v0zp5SPzGvj0sdumvlF768G9K4af9nn104W/+c3/NJkm3vwzYcKEJcVhfeCnzWZLS0sTwz8p9qusrByZPX8jgAACCCCAAAIGELg1+etvKFk5O2bll5eczraPl5gXfNDmdDr7v1kTs/BGsOeS/MVnHb0JVJkdM5wIHv1TTPzrIwd/PbvxIfPKL4ecnR8vNS/9WAwRh7t99vORmwllwEdfj598u8mcsqbkhxsRobeN5E+7VTwzRwABBBBAYMwCJH9jpuODCCCAgJYEQpr8iXfOSTGJuOOt8hz1eHFxsfSzdmnDm/QyWMlfTk6OmCnKb2AadWIeG+jpnj/xxImBqMfF+n/Q5csgvfS/B/eWGk7+Br5YMuG2B9+/9Xf+9r6avulYn8s9f6037/l7ebLsnr//elB82ufB35siMo+5y4TziBT+5eTkWCwWYr9w4jMWAggggAACCKhCoGFj6u2TJ083m4f/xMxduvajajGXu/T5s+ZHtjT/2l+aHrP0oxvBn0vyl/x29c0l3LwXcKg03Zyaf3ZkXTeyw6U7Lg0nf8+OPDn00sdPmT0mfzc+9Wt/8zfZqbOf/djn0z4zMzNHhvD8N0/71FJtz1wRQAABBBDwQ4Dkzw8kmiCAAALaFwhd8if9IMS+ffukgEdtv/MnPe2zqKhITCyktHKc4Z+ekr+0tLRgBTnyb4J83/OVBv+Oenzap/jRyspKi8Uy5tvypHv+0tLSXJ72KR3xb45eWzUWPjjhtqkr3j/W0ud0DnQd+zg9doJpSfGNLPDm7/zdeEDT1Zp1sRMSN7Y4r37z1ISbv/M3ULMx+babv/NXlm6auOSLizdGudr66ctPvXEwrLf83VydGP4R+3k92byBAAIIIIAAAvoWuPWev1vW2l+6JiZ1Y2XJynufLRF/hu/Wp326JX/Oo1mu9/yt+Ua8589X8td2rPTbOukuwOZtj3mPBp1O8SfPXZ6ZL5+2+LgL+WM/eNqn9i8AsAIEEEAAAaMLkPwZ/RvA+hFAwCACoUv+5EVjsDIeqc9g/c6fWO5KaV92drYwvEm/+Tfm0Eg3yV9+fv6YEaTzJe3IvwnyfanB2Hby8/MzMzNd5ikIQmZmZlFR0dj6dDqdYvInF3A/MubORz54tWXXG0tmRUz4j9/85rYJU5NXbCxrufnWQE3R83MiJkdETI6Y+vDLX4j/Xrv1i5cTTRP+V0TErCUbN60wDf/On9PZV1O4Inby8NM+I+ek/1fjyM8DjgwSrr9tNluwQuJ/9bX/fHyHt4n/2nXul3MjP23orRHHEUAAAQQQQACBcAr4SP6cQ+WZMfFz42PSR27YO5Ydf+/a8uGHcR59Pd49+RsSf+dvOCbsP/ZmcszK0kvOUe/5a85PNT/y5lHxUyc2LjAnb6zzRVBUVJSenu7yf9HiBwRBSE9Pd/l/aZI/g1wlYJkIIIAAAjoWIPnT8cllaQgggMC/BUKX/J07d04sGqUbp8Skx1fp6fd7wUr+iouLs7OzxWGzs7Olp4aKv/lnsVjGfOef3W632WxOp9NisZSWlrqvTIoG3d8a9YjFYpF43RuL4O7HAzqSl5eXkZHhY5SAepMay9M++b7UYGw7giCkpaVlZmbW1NSIv9F45MiRzMxMMcodW5/i/aDSratiJzabzeXImDvng6MKDH63wZGf8vPxT/5pPXnt6o1/vf7P1hNXT3858OVrfe8tFI+M2gkNEEAAAQQQQACBMAn4Sv6cQ8ey42+PWfPdyA15/eXZD5nNsxdsqXF6TP6czv7qD9YsmJucPDc5+bGVW44Np3k3fufP1z1/zqHm0vXPJt9rNpvNMXOXZn/e7OuH/pxOsepJT093ufOvuro6PT3d/f+lSf7+XUizhwACCCCAgDYFSP60ed6YNQIIIBCgQOiSv/T09LLhLT09PYgZj1i3Fw9v46/hi4uLc3JyxH7kyZ9zpAweT/gndqvR5K+ystLjP/4dv3mIehAEIT8/X/5NKyoq0tYSQiSj6W4Hv9vQu+4ulz8/bX+W2E/Tp5XJI4AAAgggYESB81sWJGYfHVTd0gVBKCoqslgsmZmZG4a3zMxMi8Xi8f+lSf4CrLZpjgACCCCAgOoESP5Ud0qYEAIIIBAKgeAmf2LRKE9fXPZdHhejeOErPu0zZ3izWCziXXrSrKQ7//Lz86WDge6IZfMPbltRUVFeXl6gvYntxTxSrMzd/yv+YOHYetb6p+x2+7nhjcxP66dSEITS0lKbzfavvnbhUOFP25/9afuzA6VZ/2w9ofWlMX8EEEAAAQQQMJzAUFtJevyCwmbVLlx8skXR8LZv3z75b/vJ50zyF4qSnD4RQAABBBAIpwDJXzi1GQsBBBBQTCC4yZ+8LNTKvs1mE+8gdIn9gjV/lxvR5FGo9HDRQMeqrq7Oz88XH3nq/t/8/HyXx/UE2j/tEVBcoLS01GKxjDkdV3z+TAABBBBAAAEEELgpUJEdHxOT+oeSUZ68qQUvkj/F6nYGRgABBBBAIEgCJH9BgqQbBBBAQN0CJH9hKLHFu9Dc/xuGoRkCAY0K2Gy2vLy8yspKjc6faSOAAAIIIIAAAvoTIPlTd3HP7BBAAAEEEBhdgORvdCNaIIAAAjoQIPnTX0HOihBAAAEEEEAAAQQQQACBoAuQ/OngCgBLQAABBBAwuADJn8G/ACwfAQSMIkDyF/R6mA4RQAABBBBAAAEEEEAAAf0JkPwZ5TIB60QAAQQQ0K8AyZ9+zy0rQwABBGQCJH/6K8hZEQIIIIAAAggggAACCCAQdAGSP1klzS4CCCCAAAKaFCD50+RpY9IIIIBAoAIkf0Gvh+kQAQQQQAABBBBAAAEEENCfAMlfoOU27RFAAAEEEFCbAMmf2s4I80EAAQRCIkDyp7+CnBUhgAACCCCAAAIIIIAAAkEXIPkLSU1OpwgggAACCIRRgOQvjNgMhQACCCgnEFDyd5ANAQQQQAABBBBAAAEEEEDAkAIkf8oV7oyMAAIIIIBAcARI/oLjSC8IIICAygUCSv76+/t7e3vtbAgggAACCCCAAAIIIIAAAtoXaPFva21tbW9vJ/lTeXXP9BBAAAEEEBhVgORvVCIaIIAAAnoQCCj5+9e//vVPNgQQQAABBBBAAAEEEEAAAV0I9Pq9ORwOkj89XAJgDQgggAACxhYg+TP2+Wf1CCBgGIGAkr/rbAgggAACCCCAAAIIIIAAAnoR+CmQjeTPMNcJWCgCCCCAgG4FSP50e2pZGAIIICAXCCj5C/pPxNMhAggggAACCCCAAAIIIICAUgL9gWwkf/JSmn0EEEAAAQS0KEDyp8WzxpwRQACBgAVI/pSqsRkXAQQQQAABBBBAAAEEEFBWIJDgr5/kL+B6mw8ggAACCCCgMgGSP5WdEKaDAAIIhEaA5E/ZSpvREUAAAQQQQAABBBBAAAGlBEj+QlNn0ysCCCCAAAIqFSD5U+mJYVoIIIBAcAVI/pSqsRkXAQQQQAABBBBAAAEEEFBWwGPyt2PHDo/HuecvuMU4vSGAAAIIIBB+AZK/8JszIgIIIKCAAMmfspU2oyOAAAIIIIAAAggggAACSgm4J3w7Rjb3t0j+FKjYGRIBBBBAAIGgCpD8BZWTzhBAAAG1CpD8KVVjMy4CCCCAAAIIIIAAAgggoKyAS7w3kvrd/NvlXZI/tZb1zAsBBBBAAAF/BUj+/JWiHQIIIKBpAZI/ZSttRkcAAQQQQAABBBBAAAEElBKQZ3susZ/4Ut6A5E/TtT+TRwABBBBAwOFwkPzxNUAAAQQMIUDyp1SNzbgIIIAAAggggAACCCCAgLIC8mBv1H2SP0NcI2CRCCCAAAK6FiD50/XpZXEIIIDAiADJn7KVNqMjgAACCCCAAAIIIIAAAkoJjJr2yRuQ/I2U0fyNAAIIIICAVgVI/rR65pg3AgggEJAAyZ9SNTbjIoAAAggggAACCCCAAALKCsiDvVH3Sf4CqrVpjAACCCCAgAoFSP5UeFKYEgIIIBB8AZI/ZSttRkcAAQQQQAABBBBAAAEElBIYNe2TNyD5C35BTo8IIIAAAgiEV4DkL7zejIYAAggoJEDyp1SNzbgIIIAAAggggAACCCCAgLIC8mBv1H2SP4WqdoZFAAEEEEAgaAIkf0GjpCMEEEBAzQKhS/72nx964jPHjK290p8nPnPsPz+kbGU7/tGtbAgggAACCCCAAAIIIICAWgUCKnnEtO/waJvYjORPzaU9c0MAAQQQQMAfAZI/f5RogwACCGheIHTJn0vsJ+Z/T3zmCKgQVWFjq9UqsCGAAAIIIIAAAggggAAC6hOwWq0B1VAkf5ov6VkAAggggAACgQiQ/AWiRVsEEEBAswKhS/6kW/1cdgIqRFXYmORPfdc3mBECCCCAAAIIIIAAAgjcECD502xpzsQRQAABBBAIhwDJXziUGQMBBBBQXIDkL9BwkeSPayoIIIAAAggggAACCCCgTgGSP8VLbCaAAAIIIICAmgVI/tR8dpgbAgggEDQBkj+SP3Ves2BWCCCAAAIIIIAAAgggEKgAyV/QSmU6QgABBBBAQI8CJH96PKusCQEEEHATIPkj+Qv0agLtEUAAAQQQQAABBBBAQJ0CJH9uJS8HEEAAAQQQQODfAiR//7ZgDwEEENCxAMkfyZ86r1kwKwQQQAABBBBAAAEEEAhUgORPx8U7S0MAAQQQQGD8AiR/4zekBwQQQEADAiR/JH+BXk2gPQIIIIAAAggggAACCKhTgORPA0U4U0QAAQQQQEA5AZI/5ewZGQEEEAijAMkfyZ86r1n4OavLP13u7O3ov/KTn+1phgACCCCAAAIIIICAjgVI/sJYTDMUAggggAAC2hMg+dPeOWPGCCCAwBgEdJP8fX/uUkLuwcf/eqSioWfUMO/j71sXbDoyK+dA++WfR23s0sBqtXq8UvDewc1z3r7n7tf+M+WdOI8NQnFw7969CQkJoehZEAS73W4ymVpaWjz2H9KhPY7o8eA7X79hzjJ9Xb3b47v6Prhq1aq4uLjbb7/9q6++cl+p7xOUm5ubkZHh/imOIIAAAggggAACCGhagORvDEUxH0EAAQQQQMA4AiR/xjnXrBQBBAwtoKfkb9HfjrqkdBu+bFycf2z26we2H251eeuXX68FMfm71Ncz9bXfJm+ILTm2I5wpVHNzc0lJSYiuTfT392/btq23t9dj/76DJY8fkR/My8tbtWqV/MjY9hVJ/qZlT/Qz3122bJlJtr3xxhujLtOjzAcffJCYmDh58uS4uLjMzEx5JwkJCR6TP9/fDZI/uSH7CCCAAAIIIICAbgRI/gxd3rN4BBBAAAEERhMg+RtNiPcRQAABXQjoO/nbdeJirbXvmcLjoU7+GtvOmrNMqz5eoZtLBqMuRCXJ36jzDEUD/5O//v7+vr6+RYsW5eTk9PX1XblyZdT5uCd/u3fvnj59+pEjR/r6+hobGwsLC+WdeEv+5G3c90n+3E04ggACCCCAAAII6ECA5E8XZTqLQAABBBBAIFQCJH+hkqVfBBBAQFUC+k7+xPv8Vrz3D/+Tv8Ky5hV//4fLDYLyl+5P+5y7YaY5yyT9ke4G+/TIh+YsU84Xf1y2dX50zqSEt6b3/mQXBOFEc9VTf38sdl3kw39N3H54m3h9YVr2xPTtloS3pmftzHiuaMmsN8zf1np4hKN0MaK1tTUhISEmJsblaZ+pqakvvfTSwoULU1JSXnzxxUuXLgmC8NFHHz3wwAPSZz///PP4+PhPPvnk8ccflw6KO3fdddeJEycEQXjiiSfi4+NdnvZ5+fLll19++e677549e3ZeXp409Pnz55988snIyMj58+e/+OKL0mMk7XZ7VlbWvffeO3369Jdeesluv7H8kpKShIQEs9kcGRmZMLwdOnRIHH3nzp2JiYlRUVEzZ87csmWLy9xcXn558v+XzKX7LAv2b0rKi3muaMkDf4nL/+6d+DenWrYtujJwpbfPbs4y/e7duZnFL8atv2vh5gdPt9aIHXo8HYIgvFycZs4y5X/3zkP/N2F6zh3Pf7BUEIRFW1KlQcUd36dJHGLx4sW5ubnS/K9cuWIymQoLC+fPn3/vvfe++uqr4lveZF599dW0tDTp4y477smft+9GU1PTokWLIiMjH3/88TVr1kinqampyWKxTJs2LS4ubvPmzfL+p0yZsmPHjvnz58cNb+LXSd6AfQQQQAABBBBAAAFVCZD8qarcZjIIIIAAAgioTYDkT21nhPkggAACIREg+ZOnek6nc90XZ5PfrHA5KH/pnvztrVDTedUAACAASURBVN3z3sF8c5Zp0ZbUXSdKpChITP7ufu0/c3f9qeTYjpwv1vb+ZLd2t8xcN2XWG+a/7s17suBhc5bpv499LAjCtOyJCzfPe/nT35uzTOtLX527YebKD58e9SKC+413qampDzzwwOXLlwVBWLlyZVZWliAIly5dioiIqK6uFjtctmzZpk2bGhsbIyIi5HehNTQ0REZGSkfcf+fvzTffnDdvXnt7e2tra2JiopT8LVy48KWXXurr6zt+/Pidd94pRUovvvjik08+2d7ebrfbn3/++T/+8Y/SitzvbLt8+fIdd9xx4MABQRC6uroqKyulxh53LnQ17zpRkvaRRf47fwX7N5mzTO9+u2FGbsQDf4l7fdcr5izTyfPHxeTPnGVat/vPRRUFU1/77aN/TRIEwdvpkJK/e9dFbSnbVHx0+ztfrxcE4eCZfbtOlEx97bcJb07bdaJk14kSa7fn30GUz9lj8rd27VpBEDo6OqKioo4dOya1d5fZuXNnZGTk+++/39DQIDWTdtyTP/Et9+/G/PnzX3755b6+vsrKykmTJomnqa+vLz4+Pjc3t6+vr7m5+b777tu5c6fU+ZQpU1JTU8Xfemxubu7r65PeYgcBBBBAAAEEEEBAhQIkfyEpm+kUAQQQQAABvQiQ/OnlTLIOBBBAwKcAyZ881fNn3z35EwThrK3O/WmfYvL36s6X5VcExIzw0yMfCoLQdsl292v/uWhLqpj85X2Vu+fULnOWqd5am77dsnDzg/IPetx3T3dSU1P/9re/iY337dt3zz33iPurV6/Ozs6+MWhb2x133HH+/HlBEKKjo0+ePHns2LEpU6ZcunSpuLh4yZIl0kDuyV9iYuLHH9/IKQVBeO+998Tkr62tzWQynTt3Tjz+wgsviJFST0+PyWSqra0Vj584cSIqKkrcFwTBPd/q7e2dPHny+++/393dLTUbdcfld/7E5K/3J/ujf01aveP52pZT5izTvtPfiMnf7DfuHhgcEATh2W1PmrNMzR0/ejsdUvK368R/u8/B/6d9ip/1mPwdP35cfPexxx7bsWOHNIq7jCAIu3fvXrp06ZQpU+Li4j766COpsSAIfiZ/LqfpueeeE0/T119/PXXq1IGBGyyCIBQUFKxY8e+H1k6ZMuWzzz6TD8c+AggggAACCCCAgJoFSP58lr+8iQACCCCAgNEFSP6M/g1g/QggYBABkj9/0j55m0CTv/fLb3lqZe6uP5mzTJWNFeL1grj1dyW8Nf1m8rcn9+vq3eYs01lb3aqPV8z/2/2jXlPwmPxt375d/ODx48d/+9vfivuHDh2aPn36lStXCgsLpXjvhRdeKCoq2rBhwyOPPPLll1+uXbt206ZN0qDuyV9UVNS+ffvEBl9++aWY/NXU1JhMJvEuQ0EQsrKyxEiptrbWZDIlyrapU6eKD/z0mPwJgnDgwIFnnnkmKioqOTn5m2++kWbiY8dz8tdn/927yf/nkxdOt9aYs0zf1JSKyZ94n58gCGv/e7U5y3Siucrb6ZCSv5Pnb+Zz8jkEJfmTbuB74okntm27+dBXbzLi6P39/Xv27Jk0aZL8hkg/kz/xNDkcDrEr6TS9//77kydPls7SrFmznnzySWmxU6ZMkY8lHWcHAQQQQAABBBBAQJ0CJH8GKeRZJgIIIIAAAmMTIPkbmxufQgABBDQmQPInT/X82Q80+SuqKJBfFJDfZHbxUtst9/zdmvz97t1k+Qc97ntM/jZs2CA2/vLLL6Ojo6UPxsfHf/PNNykpKdLjHP/+97+vXr164cKFlZWVGRkZKSkphw8fltq7J39z5sz5/PPPxQbbt2+X3/P3ww8/iMdXrlwpv+fPZrNJHcp3NmzY8OKLL8qPSPsDAwNbt26V3yAoveW+40/y93X1bjH5i10XefmnG89BXVzwiPs9f/LTISV/1Rdu/OqhyxadM+mBv8S5HPTx0uM9f96SPx8y4hCpqanypDApKam0tNR9dJfvhnjPX2trq9hS+jnGr7/+OjEx0f3j4pEpU6ZUVVV5e5fjCCCAAAIIIIAAAmoTIPnTWEHOdBFAAAEEEAivAMlfeL0ZDQEEEFBIQN/J36//uv7Lr9dW/P0fH1Rc+OXXa9eu/zva++XXa7NyDrRf/vnfh4b3tuxreqbwuMtB+ctxJn8tXedn5N45+427/7o3T8yfio/euEVvWvbEvCAlf/fee++PP/7Y09OzcOHCP//5z9LFiE2bNj3wwANRUVHSjV8nT56MiYlZvny5IAgPPfRQRESE9JYgCO7JX15e3lNPPTUwMPDTTz899thj8t/5e/nll3/66afq6uopU6aIyZ8gCGlpaS+88EJbW5sgCE1NTbt27ZIm89FHH82bN++nn36SjnR2du7Zs0e8d/CDDz6IjY2V3vK4s7d2z87jxb//8Jkbv4y4+9Wdx4uP/fD9zad93nrPn5T83f3af1q2LfrjZzdu+Hvkr3MEQfB2Onwnfw/+3/hp2RO3lRfsPF7c0nXjuanetv7+/r6+vkWLFuXk5PT19Ym/oXjlyhWTyeQt+XOX2blz5+eff97W1uZwOHbv3j1p0iR5GvfCCy+8+uqr7hNwSf4EQXj88cfffffdG6tuaYmKihJPk8PhmD179t/+9jeHw3HlypWTJ08eOnRI6o3kT6JgBwEEEEAAAQQQ0IQAyZ9ChTXDIoAAAgggoA0Bkj9tnCdmiQACCIxTQN/J3/+37cSsnAPSn8+r2qQMz1vyt+6Ls8lvVkjN3HfGmfwJgnC86eiyrfNj10Wmbrrvvw79XbyCEGjyl5ubGxcXFx0dffvtt8cNb2fOnBEEITU1NTc3NzEx8a677kpLS+vp6ZGuUFy4cOG3v/2tFMsJgjAwMBAZGSneQJaZmTl//nyx8e7du8U+TSZTbGxsXFzcJ598IgiCw+HIyMh44IEHFixY8Mc//lFK/s6fP//kk09GRUUtWLBg1apVmZmZYj92uz07OzsuLi4yMjIxMXHLln8/+LSnp2fp0qXR0dEzZ84sLy8XBKG9vf2JJ5646667zGbzI488cuTIEWnmHnce3pRozjLJ//zxs1W+k78F+Q/k7vrTjNw7F25+sLalWuzW4+nwnfztObUr5Z24adkTzVmmb2u/8jg98eCyZctMsu2NN94QBMF38ucuc/DgwccffzwqKioiIuL+++//7/++5acHGxoaHnzwwTvvvFM6fd6+G83NzYsXL3744YeXLFlisVikb8IPP/zw3HPPRUdHR0VFPfLII99++620IpI/iYIdBBBAAAEEEEBAEwIkf+MskPk4AggggAAC+hYg+dP3+WV1CCCAwE0B3SR/x5t7H/7L90s2Hzt87pJ7XOdy5NMj1iWbjz204XBn31WXt0Z96TH5U89VgNTU1OLiYo/zcTgckZGRof7ZtjVr1vzlL3/xOAEFD4pP+3w8P0XBOTA0AggggAACCCCAAAKhFiD5o9RHAAEEEEAAAR8CJH8+cHgLAQQQ0I+AbpK/URO7YDXQbvK3ZcuW5OTRfztwDBcjTp06dfbsWUEQfvjhh6lTp8qfRTmG3kLxEZK/UKjSJwIIIIAAAggggIDaBEj+9FOrsxIEEEAAAQRCIEDyFwJUukQAAQTUJ0DyF2giqMXkr6urKzIyMikpKUSZ3N69e+Pi4qZOnXrfffdt337jZwvVtpH8qe2MMB8EEEAAAQQQQACBUAiQ/Kmv5mZGCCCAAAIIqEiA5E9FJ4OpIIAAAqETIPnTWfIXissH9IkAAggggAACCCCAAAKaECD5C13tTM8IIIAAAgjoQIDkTwcnkSUggAACowuQ/JH8aeISBpNEAAEEEEAAAQQQQACBUQVI/kavgWmBAAIIIICAgQVI/gx88lk6AggYSYDkj+Rv1MsHNEAAAQQQQAABBBBAAAFNCJD8GamaZ60IIIAAAggELEDyFzAZH0AAAQS0KEDyR/KniUsYTBIBBBBAAAEEEEAAAQRGFSD502JVzpwRQAABBBAImwDJX9ioGQgBBBBQUoDkL0TJ34kTJ+Li4qZNm5aSkuKxPk9NTS0pKfH4lt1uN5lMLS0tHt/V+kHfMr7X7vtdP2UsFouL/KOPPnrgwAE/P04zBBBAAAEEEEAAAQRUK0Dyp2R1zdgIIIAAAgioXoDkT/WniAkigAACwRAg+QtR8ideCygpKfGW/O3atauhocHjJYOg5Fsee/bzYFVVlenWra+vz/dnDx48OHPmTJc2TU1Nzz333N133x0VFTV//vzDhw9LDbzJ9Pf3b9u2rbe3V2op3xm/zMGDBxMTEwcHB+XdlpWVzZ071+WgvAH7CCCAAAIIIIAAAghoQoDkLxhVMn0ggAACCCCgWwGSP92eWhaGAAIIyAVI/pRK/nxcOBh/vuWjcz/f6uvrq6ioMJlMnZ2do8Z+giB4TP6Sk5P/9Kc/dXR09PT0fPfdd/4kf76nN36Z5cuXb9682WWUwcHB2NjYsrIyl+O8RAABBBBAAAEEEEBAWwIkf/Jql30EEEAAAQQQcBEg+XMB4SUCCCCgTwGSv/Enf93d3c8///y0adPMZvOjjz7a2toqXR3weGfb+vXrExISJk2a5PLMyYKCgtjY2KlTpxYWFsqf9llUVJSYmBgVFbVo0aLGxkap84KCgmXLlm3YsCEhISE6Ojo/P196y2Wnr/vn3jbB5Y9LG/eXlZWVJpPJbrdLb+Xl5VksljVr1iQnJyclJVVXVwuC0NjYmJCQMGPGjIkTJyYMb+JMOjs7TSaTt/saPco88cQT8fHx8rWLQwcqs3z58jfffPP3v//9rFmz7rnnnkOHDon9XL58+fbbb6+pqZFWJO289NJLa9eulV6ygwACCCCAAAIIIICAFgVI/vRZt7MqBBBAAAEEgiRA8hckSLpBAAEE1C1A8jf+5O/tt99evHixw+EYGBioqqrq7OyUrhF4zLfEd11+52///v2RkZGnTp1yOBwrV66U0q/t27fPnDmztrb2ypUrW7ZsmTt37sDAgNhDQUFBREREYWGhIAiDg4PyUFCagLiz708//1ei65/Bm924tP33S4/J35133vnDDz8IgvD2228vXbpUau3xnr/ExMSnn376wIED8vhQ/Ig3Gfe7+sYgs3z58qlTp1ZWVgqCYLfbrVarOOg//vEPk8nU398vTVva2bp16yOPPCK9ZAcBBBBAAAEEEEAAAS0KkPypu/5mdggggAACCCgsQPKn8AlgeAQQQCA8AiR/40/+8vLyHnroodraWvcfivOWbwmC4JL8rV27dtWqVeLFhdraWin5mzdv3nvvvSceHxwcjIyMlG5ZKygomD17tj/XI9rrhOZDP7v8GfWDHpO/p556SvzggQMHYmNjpU48Jn9tbW3Z2dn33XffpEmTVqxYceHCBam9Nxn35G8MMsuXL3/ppZeksaSdsrKyiIgI6aV8Z8eOHfHx8fIj7COAAAIIIIAAAgggoDkBkr/w1NGMggACCCCAgEYFSP40euKYNgIIIBCYAMnf+JM/u92+bt26pKSkyMjI1atXy+9v85ZvuSd/K1asWL9+vXhloaurS0r+zGZzbGxs4sgWHR29f/9+sVlBQcHixYv9uRhxuePnnvOCy59RP+gx+UtLSxM/ePjw4alTp0qdeEz+pHdbWlosFot8tt5k3JO/McgsX75806ZN0ujSju97/h5++GGpJTsIIIAAAggggAACCGhRgOQvsHqY1ggggAACCBhMgOTPYCec5SKAgFEFSP7Gn/xJVwQuXLgwZ84c8fGb4sFdu3bdf//9UgP5jss9f6+88kpGRobYoKGhQUr+5s2bt3PnTvkHpX3xd/6klz52gvi0T2/JX0VFxYwZM3zMYe/evfKk0JuMe/I3Bpnly5d7/NVDH7/z94c//IHf+fNx+ngLAQQQQAABBBBAQBMCJH9GrexZNwIIIIAAAn4JkPz5xUQjBBBAQOsCJH/jT/7KysrE39jr6OhISkrasWOHdFGgrq4uIiLi/Pnz0hFpxyX5Ky8vj4mJ6ejoEAQhNzdXSv4+/PDDpKSkuro6QRC6uro+/fTTK1euiJ34n/y11QhNB13/SDPxuNPX11dRUWEymTo7O/v6+sQ2eXl53pK/xsbGO+64o7W1Vd7bn//855qaGofD0dzc/PTwJr3rTcY9+RuDjLfkTxCE5cuXb968WZqGuDM4OHjvvffu27fP5TgvEUAAAQQQQAABBBDQlgDJn9YrdOaPAAIIIIBASAVI/kLKS+cIIICAWgRI/saf/G3bti0+Pj4yMjImJua1116TkjnxGkFeXp7ZbJ4yZcrevXsFQWhpaYkb3iZNmjRt2rS4uLjMzEyx5datW5OTkxcsWCBP/gRBKCoqEh8lOmPGjNWrVw8MDIjt/U/+Ar1aUVVVZbp1E8M/H8mfIAjZ2dn33HPPzJkzpSdtZmRkxMXFTZo0KTo6Oj093WazyWfiIrN7925RxmQyxcbGxsXFffLJJ2OT8ZH8lZeXJyYmuvwiY1lZWVJSkstB+VTZRwABBBBAAAEEEEBAEwIkf2qptJkHAggggAACqhQg+VPlaWFSCCCAQLAFSP7Gn/xp4hIAk5QEnn322ZKSEumlIAiPPvrogQMH5EfYRwABBBBAAAEEEEBAiwIkf8GumOkPAQQQQAABXQmQ/OnqdLIYBBBAwJsAyR/JnxavaDBnBBBAAAEEEEAAAQQQcBcg+fNW+XIcAQQQQAABBBwOB8kfXwMEEEDAEAIkfyR/7tcLOIIAAggggAACCCCAAAJaFCD5M0QZzyIRQAABBBAYqwDJ31jl+BwCCCCgKQGSP5I/LV7RYM4IIIAAAggggAACCCDgLkDyp6lynMkigAACCCAQbgGSv3CLMx4CCCCgiADJH8mf+/UCjiCAAAIIIIAAAggggIAWBUj+FCmrGRQBBBBAAAGtCJD8aeVMMU8EEEBgXAIkfyR/WryiwZwRQAABBBBAAAEEEEDAXYDkb1zlMR9GAAEEEEBA7wIkf3o/w6wPAQQQGBYg+SP5c79ewBEEEEAAAQQQQAABBBDQogDJH4U+AggggAACCPgQIPnzgcNbCCCAgH4ESP5ClPydOHEiLi5u2rRpKSkpHi8ZpKamlpSUeHzLbrebTKaWlhaP73IQAQQQQAABBBBAAAEEEPAoQPKnn1qdlSCAAAIIIBACAZK/EKDSJQIIIKA+AZK/ECV/Yh1eUlLiLfnbtWtXQ0ODx3Kd5M8jCwcRQAABBBBAAAEEEEDAtwDJn/pqbmaEAAIIIICAigRI/lR0MpgKAgggEDoBkj+lkj8fFTvJnw8c3kIAAQQQQAABBBBAAAFvAiR/oaud6RkBBBBAAAEdCJD86eAksgQEEEBgdAGSv/Enf93d3c8///y0adPMZvOjjz7a2toq1eEe7/lbv359QkLCpEmTXJ72WVBQEBsbO3Xq1MLCQvnTPouKihITE6OiohYtWtTY2Ch1XlBQsGzZsg0bNiQkJERHR+fn50tvsYMAAggggAACCCCAAAIGFCD5G70GpgUCCCCAAAIGFiD5M/DJZ+kIIGAkAZK/8Sd/b7/99uLFix0Ox8DAQFVVVWdnp3SJwWPyJ77r8jt/+/fvj4yMPHXqlMPhWLlypZT8bd++febMmbW1tVeuXNmyZcvcuXMHBgbEHgoKCiIiIgoLCwVBGBwclIeC0gTYQQABBBBAAAEEEEAAAeMIkPwZqZpnrQgggAACCAQsQPIXMBkfQAABBLQoQPI3/uQvLy/voYceqq2tHRwcdLmm4H/yt3bt2lWrVokfr62tlZK/efPmvffee+LxwcHByMjImpoa8WVBQcHs2bNdRuQlAggggAACCCCAAAIIGFaA5E+LVTlzRgABBBBAIGwCJH9ho2YgBBBAQEkBkr/xJ392u33dunVJSUmRkZGrV6+22+3ShQb/k78VK1asX79e/GBXV5eU/JnN5tjY2MSRLTo6ev/+/WKzgoKCxYsXS2OxgwACCCCAAAIIIIAAAgYXIPlTsrpmbAQQQAABBFQvQPKn+lPEBBFAAIFgCJD8jT/5ky4uXLhwYc6cOeLjN8WDu3btuv/++6UG8h2Xp32+8sorGRkZYoOGhgYp+Zs3b97OnTvlH5T2xd/5k16ygwACCCCAAAIIIIAAAgYXIPkLRpVMHwgggAACCOhWgORPt6eWhSGAAAJyAZK/8Sd/ZWVl4m/sdXR0JCUl7dixQ7rcUFdXFxERcf78eemItOOS/JWXl8fExHR0dAiCkJubKyV/H374YVJSUl1dnSAIXV1dn3766ZUrV8ROSP4kTHYQQAABBBBAAAEEEEBAEASSP3m1yz4CCCCAAAIIuAiQ/LmA8BIBBBDQpwDJ3/iTv23btsXHx0dGRsbExLz22mtSMideesjLyzObzVOmTNm7d68gCC0tLXHD26RJk6ZNmxYXF5eZmSm23Lp1a3Jy8oIFC+TJnyAIRUVF4qNEZ8yYsXr16oGBAbE9yR8XdxBAAAEEEEAAAQQQQEAuQPKnz7qdVSGAAAIIIBAkAZK/IEHSDQIIIKBuAZK/8Sd/8kqbfQQQQAABBBBAAAEEEEBAKQGSP3XX38wOAQQQQAABhQVI/hQ+AQyPAAIIhEeA5I/kT6mrEoyLAAIIIIAAAggggAACwRUg+QtPHc0oCCCAAAIIaFSA5E+jJ45pI4AAAoEJkPyR/AX3WgO9IYAAAggggAACCCCAgFICJH+B1cO0RgABBBBAwGACJH8GO+EsFwEEjCpA8kfyp9RVCcZFAAEEEEAAAQQQQACB4AqQ/Bm1smfdCCCAAAII+CVA8ucXE40QQAABrQuQ/JH8BfdaA70hgAACCCCAAAIIIICAUgIkf1qv0Jk/AggggAACIRUg+QspL50jgAACahEg+SP5U+qqBOMigAACCCCAAAIIIIBAcAVI/tRSaTMPBBBAAAEEVClA8qfK08KkEEAAgWALkPyR/AX3WgO9IYAAAggggAACCCCAgFICJH/BrpjpDwEEEEAAAV0JkPzp6nSyGAQQQMCbAMkfyZ9SVyUYFwEEEEAAAQQQQAABBIIrQPLnrfLlOAIIIIAAAgg4HA6SP74GCCCAgCEEQpf8PfGZY8bWXpc/T3zmCDRpU1t7q9Ua3OKc3hBAAAEEEEAAAQQQQACBoAiQ/BmijGeRCCCAAAIIjFWA5G+scnwOAQQQ0JRA6JK//eeHXMK/Jz5z7D8/pLYkL9D5WNkQQAABBBBAAAEEEEAAAbUKBFTg9A9vh0fbxGZVVVX19fVNTU02m629vb27u7unp8dut/f29rrXlZoqi5ksAggggAACRhEg+TPKmWadCCBgcAH3Cq23t9dut/f09HR3d7e3t9tstqampvr6+qqqqoBqSBojgAACCCCAAAIIIIAAAgioWYDkz+AXBFg+AggggIDRBEj+jHbGWS8CCBhUgORPzXU4c0MAAQQQQAABBBBAAAEEQidA8mfQCwEsGwEEEEDAqAIkf0Y986wbAQQMJkDyF7oqmp4RQAABBBBAAAEEEEAAATULkPwZ7AIAy0UAAQQQMLoAyZ/RvwGsHwEEDCJA8qfmOpy5IYAAAggggAACCCCAAAKhEyD5M0jhzzIRQAABBBAQBUj++CYggAAChhAg+QtdFU3PCCCAAAIIIIAAAggggICaBUj+DFH2s0gEEEAAAQRGBEj+RiT4GwEEENC1QOiSv8Otvzy1s2/G1l7pz+8+cRxu/UXNdS9zQwABBBBAAAEEEEAAAQSMI0Dyp+tyn8UhgAACCCDgKkDy5yrCawQQQECXAqFL/n73iUPK/KSdp3b2GaeKZqUIIIAAAggggAACCCCAgJoFSP50WeazKAQQQAABBLwJkPx5k+E4AgggoCuB0CV/UtrnsqPmupe5IYAAAggggAACCCCAAALGESD501V5z2IQQAABBBAYTYDkbzQh3kcAAQR0IUDyZ5yqnpUigAACCCCAAAIIIIAAAnIBkj9dlPUsAgEEEEAAAX8FSP78laIdAgggoGkBkj953cs+AggggAACCCCAAAIIIGAcAZI/TZfzTB4BBBBAAIFABUj+AhWjPQIIIKBJAZI/41T1rBQBBBBAAAEEEEAAAQQQkAuQ/GmyjGfSCCCAAAIIjFWA5G+scnwOAQQQ0JQAyZ+87mUfAQQQQAABBBBAAAEEEDCOAMmfpsp3JosAAggggMB4BUj+xivI5xFAAAFNCJD8GaeqZ6UIIIAAAggggAACCCCAgFyA5E8TZTuTRAABBBBAIFgCJH/BkqQfBBBAQNUCJH/yupd9BBBAAAEEEEAAAQQQQMA4AiR/qi7XmRwCCCCAAALBFiD5C7Yo/SGAAAKqFCD5M05Vz0oRQAABBBBAAAEEEEAAAbkAyZ8qy3QmhQACCCCAQKgESP5CJUu/CCCAgKoESP7kdS/7IRW4du3ahQsXTp8+XTm8nT59uqWl5fr16yEdlM4RQAABBBBAAAEEEEDAmwDJn6rKcyaDAAIIIIBAqAVI/kItTP8IIICAKgRI/rzVwBwPrkBXV1dFRUVbW1tvb+/Q8Nbb22uz2SoqKrq7u4M7Fr0hgAACCCCAAAIIIICAPwIkf6ooy5kEAggggAAC4RIg+QuXNOMggAACigqQ/PlTD9NmnAKdnZ1nzpzx1kl9fX1XV5e3dzmOAAIIIIAAAggggAACIRIg+VO0HGdwBBBAAAEEwi1A8hduccZDAAEEFBEg+QtRCU23kkBXV5eP2E9sVl9fz51/kpgWd06fPj1x4sQ9e/aIk+/v71+9erXZbI6Ojn733Xe1uCLmjAACCCCAAAIIGEGA5E+RMpxBEUAAAQQQUEqA5E8pecZFAAEEwipA8meEel7BNV67dq2iosKfCZSXl/Obf/5AqbDN0NBQSkrKrFmzpORv1apVmZmZQ0ND7e3tDz/8cGNjowqnzZQQQAABBBBAAAEESP7CWn4zGAIIIIAAAkoLkPwpfQYYHwEEEAiLAMkf1X5Ink1oTwAAIABJREFUBS5cuNDW1ubPEFartbW11Z+WtFGbwFtvvZWXl7d06VIx+bt8+fLkyZMdDofa5sl8EEAAAQQQQAABBFwESP7CUnYzCAIIIIAAAmoRIPlTy5lgHggggEBIBUj+XErfcb48yHarwPfff9/b2+uPqt1ur6ysvPXTvApAwB/kULQ5depUSkrK0NCQlPwdOXIkISFh8+bNiYmJc+fO/eCDD0IxLn0igAACCCCAAAIIjF+A5C+k5TadI4AAAgggoDYBkj+1nRHmgwACCIREgORv/NWyvIcAghpjND106NDQ0JCcyNv+0NDQoUOHjKESklV6gw3p8atXryYnJ58+fdrpdErJ3969e2+//fYdO3Zcv369qakpOjr6wIEDIZ0GnSOAAAIIIIAAAgiMTYDkLyRlNp0igAACCCCgVgGSP7WeGeaFAAIIBFWA5G9sFbK3T4Uk0tFypwElfxUVFVpeq8Jz9/adDOnx3NzcjRs3ikNIyd/Ro0cjIyOlcV9//fWsrCzpJTsIIIAAAggggAAC6hEg+QtqeU1nCCCAAAIIqF2A5E/tZ4j5IYAAAkERIPkLbtWtcPijvuEDetrn999/r74VaGZGwf0m+9lbbGxsXFzcrOFt8uTJ06dPf+edd9rb2ydOnCgIgthJTk5Obm6unx3SDAEEEEAAAQQQQCCcAiR/QSmr6QQBBBBAAAGtCJD8aeVMMU8EEEBgXAIkf+Gsqw04VktLS1tbmz8Lt1qtra2t/rSkjToFpHv+nE7n008/nZub++uvv7a0tERHRx8+fFidc2ZWCCCAAAIIIICAwQVI/sZVTvNhBBBAAAEEtCZA8qe1M8Z8EUAAgTEJkPwZvNQP9fKvX79eUVHhzyjl5eX+NKONagXkyV9nZ+czzzxz1113zZ49+8MPP1TtnJkYAggggAACCCBgcAGSvzGV0XwIAQQQQAABrQqQ/Gn1zDFvBBBAICABkj+Dl/phWH53d/eZM2d8D1RXV9fT0+O7De8igAACCCCAAAIIIIBAcAVI/gIqn2mMAAIIIICA1gVI/rR+Bpk/Aggg4JcAyV9wK2d68yjQ1dVVX1/v8S2n01lXV9fd3e3tXY4jgAACCCCAAAIIIIBAiARI/vwqm2mEAAIIIICAXgRI/vRyJlkHAggg4FOA5C9EJTTdugh0d3eXl5dbrVa73T40vNntdpvNVl5ezt1+Lla8RAABBBBAAAEEEEAgPAIkfz7LZd5EAAEEEEBAbwIkf3o7o6wHAQQQ8ChA8heeippRnE7n9evXW1tb6+rqjhw5UllZefr06dbWVmQQQAABBBBAAAEEEEBAKQGSP49lMgcRQAABBBDQqwDJn17PLOtCAAEEbhEg+VOqxmZcBBBAAAEEEEAAAQQQQEBZAZK/W8pjXiCAAAIIIKB3AZI/vZ9h1ocAAggMC5D8KVtpMzoCCCCAAAIIIIAAAgggoJQAyR8XBhBAAAEEEDCUAMmfoU43i0UAAeMKkPwpVWMzLgIIIIAAAggggAACCCCgrADJn3GvBbByBBBAAAFDCpD8GfK0s2gEEDCeAMmfspU2oyOAAAIIIIAAAggggAACSgmQ/BnvGgArRgABBBAwtADJn6FPP4tHAAHjCJD8KVVjMy4CCCCAAAIIIIAAAgggoKwAyZ9xan9WigACCCCAgMPhIPnja4AAAggYQoDkT9lKm9ERQAABBBBAAAEEEEAAAaUESP4MUfazSAQQQAABBEYESP5GJPgbAQQQ0LUAyZ9SNTbjIoAAAggggAACCCCAAALKCpD86brcZ3EIIIAAAgi4CpD8uYrwGgEEENClAMmfspU2oyOAAAIIIIAAAggggAACSgmQ/OmyzGdRCCCAAAIIeBMg+fMmw3EEEEBAVwKhS/5+94ljxtZelz/LPu9TqqZlXAQQQAABBBBAAAEEEEAAAbkAyZ+uynsWgwACCCCAwGgCJH+jCfE+AgggoAuB0CV/h1t/WfZ5nzz5+90njsOtv8jrTPYRQAABBBBAAAEEEEAAAQSUEiD500VZzyIQQAABBBDwV4Dkz18p2iGAAAKaFghd8qdU7cq4CCCAAAIIIIAAAggggAAC/giQ/Gm6nGfyCCCAAAIIBCpA8heoGO0RQAABTQqQ/PlTD9MGAQQQQAABBBBAAAEEENCfAMmfJst4Jo0AAggggMBYBUj+xirH5xBAAAFNCZD86a96Z0UIIIAAAggggAACCCCAgD8CJH+aKt+ZLAIIIIAAAuMVIPkbryCfRwABBDQhQPLnTz1MGwQQQAABBBBAAAEEEEBAfwIkf5oo25kkAggggAACwRIg+QuWJP0ggAACqhYg+dNf9c6KEEAAAQQQQAABBBBAAAF/BEj+VF2uMzkEEEAAAQSCLUDyF2xR+kMAAQRUKUDy5089TBsEEEAAAQQQQAABBBBAQH8CJH+qLNOZFAIIIIAAAqESIPkLlSz9IoAAAqoSIPnTX/XOihBAAAEEEEAAAQQQQAABfwRI/lRVnjMZBBBAAAEEQi1A8hdqYfpHAAEEVCFA8udPPUwbBBBAAAEEEEAAAQQQQEB/AiR/qijLmQQCCCCAAALhEiD5C5c04yCAAAKKCpD86a96Z0UIIIAAAggggAACCCCAgD8CJH+KluMMjgACCCCAQLgFSP7CLc54CCCAgCICJH/+1MO0QQABBBBAAAEEEEAAAQT0J0Dyp0gZzqAIIIAAAggoJUDyp5Q84yKAAAJhFSD5C7R6t7IhgAACCCCAAAIIIIAAAmoVCKjAIfkLa/nNYAgggAACCCgtQPKn9BlgfAQQQCAsAiR/ARXGTqfTarUKbAgggAACCCCAAAIIIICA+gSsVmtABQ7JX1jKbgZBAAEEEEBALQIkf2o5E8wDAQQQCKkAyV9AhTHJn/oubjAjBBBAAAEEEEAAAQQQuClA8hfS8pnOEUAAAQQQ0LoAyZ/WzyDzRwABBPwSIPkj+eMyCQIIIIAAAggggAACCOhDgOTPrzKYRggggAACCBhVgOTPqGeedSOAgMEESP5I/vRxjYNVIIAAAggggAACCCCAAMmfwQp6losAAggggEBgAiR/gXnRGgEEENCoAMkfyR/XRxBAAAEEEEAAAQQQQEAfAiR/Gi3MmTYCCCCAAALhESD5C48zoyCAAAIKC5D8kfzp4xoHq0AAAQQQQAABBBBAAAGSP4ULbIZHAAEEEEBA3QIkf+o+P8wOAQQQCJIAyR/JH9dHEEAAAQQQQAABBBBAQB8CJH9BKpTpBgEEEEAAAX0KkPzp87yyKgQQQMBFgOSP5E8f1zhYBQIIIIAAAggggAACCJD8uRS8vEQAAQQQQAABuQDJn1yDfQQQQEC3ArpJ/jo7O/fs2bNv376Ojo5Rw7wff/yxrKystLR0cHBw1MYuDaxWqz8XFE6cOBEXFzdt2rSUlBSP7VNTU0tKSjy+ZbfbTSZTS0uLx3c5iAACCCCAAAIIIIAAAgh4FCD5023pzsIQQAABBBAIhgDJXzAU6QMBBBBQvYCekr/9+/fLUzqHw3H06NG9e/d+/fXXVVVVAwMD8nevXbsW0uRPrMNLSkq8JX+7du1qaGjwWK6T/Hlk4SACCCCAAAIIIIAAAgj4FiD5U30JzgQRQAABBBBQUoDkT0l9xkYAAQTCJqDj5K+jo6OlpWVgYODnn38+efJkWVmZqpI/HxU7yZ8PHN5CAAEEEEAAAQQQQAABbwIkf2ErpRkIAQQQQAABLQqQ/GnxrDFnBBBAIGABHSd/8pyvr6+vtLT0559/lg56u+fv7Nmzhw4dkpq577g/7bO7u/v555+fNm2a2Wx+9NFHW1tbpTrc4z1/69evT0hImDRpksvTPgsKCmJjY6dOnVpYWCh/2mdRUVFiYmJUVNSiRYsaGxulzgsKCpYtW7Zhw4aEhITo6Oj8/HzpLXYQQAABBBBAAAEEEEDAgAIkfwGXxHwAAQQQQAABIwmQ/BnpbLNWBBAwsIBBkr+Wlpbvvvvu+vXrUpLnLfk7derUV199JTVz33FP/t5+++3Fixc7HI6BgYGqqqrOzk7pEoPH5E981+V3/vbv3x8ZGXnq1CmHw7Fy5Uop+du+ffvMmTNra2uvXLmyZcuWuXPnDgwMiD0UFBREREQUFhYKgjA4OCgPBaUJsIMAAggggAACCCCAAALGESD5M3Bxz9IRQAABBBAYXYDkb3QjWiCAAAI6EDBC8jcwMLB3796enh55jOct+ZO38bjvnvzl5eU99NBDtbW1g4ODLtcU/E/+1q5du2rVKvHjtbW1UvI3b9689957Tzw+ODgYGRlZU1MjviwoKJg9e7bLiLxEAAEEEEAAAQQQQAABwwqQ/OmgSGcJCCCAAAIIhE6A5C90tvSMAAIIqEhA98nf4ODgvn372traXGK8ICZ/drt93bp1SUlJkZGRq1evttvt0oUG/5O/FStWrF+/XvxgV1eXlPyZzebY2NjEkS06Onr//v1is4KCgsWLF0tjsYMAAggggAACCCCAAAIGFyD5U1GxzVQQQAABBBBQnwDJn/rOCTNCAAEEQiCg7+RvcHCwrKzs4sWLLrGf0+kMYvInXVy4cOHCnDlzxMdvigd37dp1//33Sw3kOy5P+3zllVcyMjLEBg0NDVLyN2/evJ07d8o/KO2Lv/MnvWQHAQQQQAABBBBAAAEEDC5A8heCopkuEUAAAQQQ0I8AyZ9+ziUrQQABBHwI6Dj5GxgY2Ldvn9VqvTayyfM/b8nf2bNnKyoq5C1d9t2f9llWVib+xl5HR0dSUtKOHTukyw11dXURERHnz5+Xjkg7LslfeXl5TExMR0eHIAi5ublS8vfhhx8mJSXV1dUJgtDV1fXpp59euXJF7ITkT8JkBwEEEEAAAQQQQAABBARBIPnzUfzyFgIIIIAAAgiQ/PEdQAABBAwhoOPkr6GhofTWzeFwSDGet+Tv1KlTX331ldTMfcc9+du2bVt8fHxkZGRMTMxrr70mJXPipYe8vDyz2TxlypS9e/cKgtDS0hI3vE2aNGnatGlxcXGZmZliy61btyYnJy9YsECe/AmCUFRUJD5KdMaMGatXrx4YGBDbk/xxcQcBBBBAAAEEEEAAAQTkAiR/hijjWSQCCCCAAAJjFSD5G6scn0MAAQQ0JaCb5K+np+fbb789cOBAZ2ene1zncqSpqenAgQNiFOfy1qgv3ZM/eaXNPgIIIIAAAggggAACCCCglADJn6bKcSaLAAIIIIBAuAVI/sItzngIIICAIgK6Sf5GTeyC1YDkT6mrGIyLAAIIIIAAAggggAACvgVI/hQpqxkUAQQQQAABrQiQ/GnlTDFPBBBAYFwCJH+BJoIkf76vNfAuAggggAACCCCAAAIIKCVA8jeu8pgPI4AAAgggoHcBkj+9n2HWhwACCAwLkPyR/Cl1VYJxEUAAAQQQQAABBBBAILgCJH8U+ggggAACCCDgQ4DkzwcObyGAAAL6ESD5I/kL7rUGekMAAQQQQAABBBBAAAGlBEj+9FOrsxIEEEAAAQRCIEDyFwJUukQAAQTUJ0DyR/Kn1FUJxkUAAQQQQAABBBBAAIHgCpD8qa/mZkYIIIAAAgioSIDkT0Ung6kggAACoRMg+SP5C+61BnpDAAEEEEAAAQQQQAABpQRI/kJXO9MzAggggAACOhAg+dPBSWQJCCCAwOgCJH8kf0pdlWBcBBBAAAEEEEAAAQQQCK4Ayd/oNTAtEEAAAQQQMLAAyZ+BTz5LRwABIwmQ/JH8BfdaA70hgAACCCCAAAIIIICAUgIkf0aq5lkrAggggAACAQuQ/AVMxgcQQAABLQqQ/I0h+bOyIYAAAggggAACCCCAAAKqFAiowOkf3g6PtonNqqqq6uvrm5qabDZbe3t7d3d3T0+P3W7v7e11ryu1WB0zZwQQQAABBHQvQPKn+1PMAhFAAIEbAu4VWm9vr91u7+np6e7ubm9vt9lsTU1N9fX1VVVVAdWQNEYAAQQQQAABBBBAAAEEEFCzAMkf1wUQQAABBBAwlADJn6FON4tFAAHjCpD8qbkOZ24IIIAAAggggAACCCCAQOgESP6Mey2AlSOAAAIIGFKA5M+Qp51FI4CA8QRI/kJXRdMzAggggAACCCCAAAIIIKBmAZI/410DYMUIIIAAAoYWIPkz9Oln8QggYBwBkj811+HMDQEEEEAAAQQQQAABBBAInQDJn3Fqf1aKAAIIIICAw+Eg+eNrgAACCBhCgOQvdFU0PSOAAAIIIIAAAggggAACahYg+TNE2c8iEUAAAQQQGBEg+RuR4G8EEEBA1wIkf2quw5kbAggggAACCCCAAAIIIBA6AZI/XZf7LA4BBBBAAAFXAZI/VxFeI4AAAroUIPkLXRVNzwgggAACCCCAAAIIIICAmgVI/nRZ5rMoBBBAAAEEvAmQ/HmT4TgCCCCgKwGSPzXX4cwNAQQQQAABBBBAAAEEEAidAMmfrsp7FoMAAggggMBoAiR/ownxPgIIIKALAZK/0FXR9IwAAggggAACCCCAAAIIqFmA5E8XZT2LQAABBBBAwF8Bkj9/pWiHAAIIaFqA5E/NdThzQwABBBBAAAEEEEAAAQRCJ0Dyp+lynskjgAACCCAQqADJX6BitEcAAQQ0KUDyF7oqmp4RQAABBBBAAAEEEEAAATULkPxpsoxn0ggggAACCIxVgORvrHJ8DgEEENCUAMmfmutw5oYAAggggAACCCCAAAIIhE6A5E9T5TuTRQABBBBAYLwCJH/jFeTzCCCAgCYESP5CV0XTMwIIIIAAAggggAACCCCgZgGSP02U7UwSAQQQQACBYAmQ/AVLkn4QQAABVQuQ/Km5DmduCCCAAAIIIIAAAggggEDoBEj+VF2uMzkEEEAAAQSCLUDyF2xR+kMAAQRUKUDyF7oqmp4RQAABBBBAAAEEEEAAATULkPypskxnUggggAACCIRKgOQvVLL0iwACCKhKgORPzXW4zuZ27dq1CxcunD59unJ4O336dEtLy/Xr13W2TJaDAAIIIIAAAggggIBWBEj+VFWeMxkEEEAAAQRCLUDyF2ph+kcAAQRUIUDyp5WaXOvz7OrqqqioaGtr6+3tHRreent7bTZbRUVFd3e31lfH/BFAAAEEEEAAAQQQ0KIAyZ8qynImgQACCCCAQLgESP7CJc04CCCAgKICJH9arM81N+fOzs4zZ854m3Z9fX1XV5e3dzmOAAIIIIAAAggggAACIRIg+VO0HGdwBBBAAAEEwi1A8hduccZDAAEEFBEg+QtRCU23kkBXV5eP2E9sVl9fz51/kpgWd06fPj1x4sQ9e/aIk+/v71+9erXZbI6Ojn733Xe1uCLmjAACCCCAAAIIGEGA5E+RMpxBEUAAAQQQUEqA5E8pecZFAAEEwipA8meEel7BNV67dq2iosKfCZSXl/Obf/5AqbDN0NBQSkrKrFmzpORv1apVmZmZQ0ND7e3tDz/8cGNjowqnzZQQQAABBBBAAAEESP7CWn4zGAIIIIAAAkoLkPwpfQYYHwEEEAiLAMkf1X5IBS5cuNDW1ubPEFartbW11Z+WtFGbwFtvvZWXl7d06VIx+bt8+fLkyZMdDofa5sl8EEAAAQQQQAABBFwESP7CUnYzCAIIIIAAAmoRIPlTy5lgHggggEBIBUj+XErfcb48yHarwPfff9/b2+uPqt1ur6ysvPXTvApAwB/kULQ5depUSkrK0NCQlPwdOXIkISFh8+bNiYmJc+fO/eCDD0IxLn0igAACCCCAAAIIjF+A5C+k5TadI4AAAgggoDYBkj+1nRHmgwACCIREgORv/NWyvIcAghpjND106NDQ0JCcyNv+0NDQoUOHjKESklV6gw3p8atXryYnJ58+fdrpdErJ3969e2+//fYdO3Zcv369qakpOjr6wIEDIZ0GnSOAAAIIIIAAAgiMTYDkLyRlNp0igAACCCCgVgGSP7WeGeaFAAIIBFWA5G9sFbK3T4Uk0tFypwElfxUVFVpeq8Jz9/adDOnx3NzcjRs3ikNIyd/Ro0cjIyOlcV9//fWsrCzpJTsIIIAAAggggAAC6hEg+QtqeU1nCCCAAAIIqF2A5E/tZ4j5IYAAAkERIPkLbtWtcPijvuEDetrn999/r74VaGZGwf0m+9lbbGxsXFzcrOFt8uTJ06dPf+edd9rb2ydOnCgIgthJTk5Obm6unx3SDAEEEEAAAQQQQCCcAiR/QSmr6QQBBBBAAAGtCJD8aeVMMU8EEEBgXAIkf+Gsqw04VktLS1tbmz8Lt1qtra2t/rSkjToFpHv+nE7n008/nZub++uvv7a0tERHRx8+fFidc2ZWCCCAAAIIIICAwQVI/sZVTvNhBBBAAAEEtCZA8qe1M8Z8EUAAgTEJkPwZvNQP9fKvX79eUVHhzyjl5eX+NKONagXkyV9nZ+czzzxz1113zZ49+8MPP1TtnJkYAggggAACCCBgcAGSvzGV0XwIAQQQQAABrQqQ/Gn1zDFvBBBAICABkj+Dl/phWH53d/eZM2d8D1RXV9fT0+O7De8igAACCCCAAAIIIIBAcAVI/gIqn2mMAAIIIICA1gVI/rR+Bpk/Aggg4JcAyV9wK2d68yjQ1dVVX1/v8S2n01lXV9fd3e3tXY4jgAACCCCAAAIIIIBAiARI/vwqm2mEAAIIIICAXgRI/vRyJlkHAggg4FOA5C9EJTTdugh0d3eXl5dbrVa73T40vNntdpvNVl5ezt1+Lla8RAABBBBAAAEEEEAgPAIkfz7LZd5EAAEEEEBAbwIkf3o7o6wHAQQQ8ChA8heeippRnE7n9evXW1tb6+rqjhw5UllZefr06dbWVmQQQAABBBBAAAEEEEBAKQGSP49lMgcRQAABBBDQqwDJn17PLOtCAAEEbhEg+VOqxmZcBBBAAAEEEEAAAQQQQEBZAZK/W8pjXiCAAAIIIKB3AZI/vZ9h1ocAAggMC5D8KVtpMzoCCCCAAAIIIIAAAgggoJQAyR8XBhBAAAEEEDCUAMmfoU43i0UAAeMKkPwpVWMzLgIIIIAAAggggAACCCCgrADJn3GvBbByBBBAAAFDCpD8GfK0s2gEEDCeAMmfspU2oyOAAAIIIIAAAggggAACSgmQ/BnvGgArRgABBBAwtADJn6FPP4tHAAHjCJD8KVVjMy4CCCCAAAIIIIAAAgggoKwAyZ9xan9WigACCCCAgMPhIPnja4AAAggYQoDkT9lKm9ERQAABBBBAAAEEEEAAAaUESP4MUfazSAQQQAABBEYESP5GJPgbAQQQ0LUAyZ9SNTbjIoAAAggggAACCCCAAALKCpD86brcZ3EIIIAAAgi4CpD8uYrwGgEEENClAMmfspU2oyOAAAIIIIAAAggggAACSgmQ/OmyzGdRCCCAAAIIeBMg+fMmw3EEEEBAVwIkf0rV2IyLAAIIIIAAAggggAACCCgrQPKnq/KexSCAAAIIIDCaAMnfaEK8jwACCOhCgORP2Uqb0RFAAAEEEEAAAQQQQAABpQRI/nRR1rMIBBBAAAEE/BUg+fNXinYIIICApgVI/pSqsRkXAQQQQAABBBBAAAEEEFBWgORP0+U8k0cAAQQQQCBQAZK/QMVojwACCGhSgORP2Uqb0RFAAAEEEEAAAQQQQAABpQRI/jRZxjNpBBBAAAEExipA8jdWOT6HAAIIaEqA5E+pGptxEUAAAQQQQAABBBBAAAFlBUj+NFW+M1kEEEAAAQTGK0DyN15BPo8AAghoQoDkT9lKm9ERQAABBBBAAAEEEEAAAaUESP40UbYzSQQQQAABBIIlQPIXLEn6QQABBFQtQPKnVI3NuAgggAACCCCAAAIIIICAsgIkf6ou15kcAggggAACwRYg+Qu2KP0hgAACqhQg+VO20mZ0BBBAAAEEEEAAAQQQQEApAZI/VZbpTAoBBBBAAIFQCZD8hUqWfhFAAAFVCZD8KVVjMy4CCCCAAAIIIIAAAgggoKwAyZ+qynMmgwACCCCAQKgFSP5CLUz/CCCAgCoESP6UrbQZHQEEEEAAAQQQQAABBBBQSoDkTxVlOZNAAAEEEEAgXAIkf+GSZhwEEEBAUQGSP6VqbMZFAAEEEEAAAQQQQAABBJQVIPlTtBxncAQQQAABBMItQPIXbnHGQwABBBQRIPlTttJmdAQQQAABBBBAAAEEEEBAKQGSP0XKcAZFAAEEEEBAKQGSP6XkGRcBBBAIqwDJX6A1tpUNAQQQQAABBBBAAAEEEFCrQEAFDslfWMtvBkMAAQQQQEBpAZI/pc8A4yOAAAJhESD5C6gwdjqdVqtVYEMAAQQQQAABBBBAAAEE1CdgtVoDKnBI/sJSdjMIAggggAACahEg+VPLmWAeCCCAQEgFSP4CKoxJ/tR3cYMZIYAAAggggAACCCCAwE0Bkr+Qls90jgACCCCAgNYFSP60fgaZPwIIIOCXAMnf/2PvTZyiuva973/hvE/VU+/71HPv81zPOXVPSFDUVlFpBkEGweAUwQkNBmI0aDQah2g0SoxjnOIQTS4apzhEbegGmmZsBpkUZJBR5pluuulhnTr31j1Vb7XLLLd7aBpoEPDbRenav732Wr/9WcPutb+91oLyh9ckIAACIAACIAACIAACIAACE4MAlD+HhsGIBAIgAAIgAALvKgEof+9qyeO+QQAE3jECUP6g/E2Mdxy4CxAAARAAARAAARAAARAAASh/79iAHrcLAiAAAiAAAoMjAOVvcLwQGwRAAATGKQEof1D+8H4EBEAABEAABEAABEAABEBgYhCA8jdOB+ZwGwRAAARAAARGhwCUv9HhjFxAAARA4C0TgPIH5W9ivOPAXYAACIAACIAACIAACIAACED5e8sDbGQPAiAAAiAAAmObAJS/sV0+8A4EQAAEnEQAyh+UP7wfAQEQAAEQAAEQAAEQAAEQmBgEoPw5aaCMZEAABEAABEBgYhKA8jcxyxV3BQIgAAI8AlD+oPxNjHcco3nAwiO1AAAgAElEQVQXJoupU9/R168fzUyRFwiAAAiAAAiAAAiAAAgMSADKH2/Ai0MQAAEQAAEQAAEuASh/XBoIgwAIgMCEJTBhlL/Ozs6EhISUlJSOjo4Bxbza2lqNRqNQKKxW64CReRGam5tFx9uX03/0PTJz6jd/DjrhIRphHBnT09NnzJgxOg577Uq8kV7L8uo1mP4UfutFex+zDDYwdbPi/Y0P/xR+q0tvGuy1DsbPqNC47ZsU+2ivg/ERDQRAAARAAARAAARAAARGhwCUvwk7dMeNgQAIgAAIgIAzCED5cwZFpAECIAACY57ARFL+UlNTuSqdwWDQarUqlSoxMTEvL89kMnHP/vOf/3Si8tdr7Jn2zV/8j825+/iG6umjURjVnzt3bhLns2jRIpppWFgYNU+ePHn58uW5ubkDOrNs2bLr169zo71F5c9ktp5PqNAZzFx/Bht+0d438ZS/6fv/6qCofP369cEKt0ePHt28efNgOSM+CIAACIAACIAACIDAWCMA5W/MD8HhIAiAAAiAAAi8TQJQ/t4mfeQNAiAAAqNGYAIrf3//+98NBsM/Xn6qq6vVavXIKX9VrZVu+yZtvv7JqI38LRaL0Wg8ceJESEiI0Wjs7++nWYeFhcXGxprN5vb29l27dk2ePFmn09n3akwpf/ZddfDsSCt/Drrh3GhQ/pzLE6mBAAiAAAiAAAiAwIQkAOVv1IbSyAgEQAAEQAAExiMBKH/jsdTgMwiAAAgMmsAEVv64Ol9zc7NCofiv//ovZpSa81dZWZmVlcWiCQPC1T7nH5vttm8S+2MTs27lXnXbN+nAg51rLi2ZceBv3t/L9P02Ea6oPj/ip6VzDrl+eHrer9qf6RuH6fv/+vmvkd7fy/bd3xH1yyr5d27JpcoBX0acOnVq4cKF3GhhYWHfffcdtVRXV0+aNKm4uPjatWuBgYEs2r1797y8vAghe/fu9fb2fu+992QymffLT1+fbZlNOufvwoUL06ZNmzFjxp07d+i1Fovl2LFjc+fOnTZt2ieffMJQLFu27ODBg6tWrfL29l61alV3dzfLSzSgLm6etS3hX9bd/fxinsdXKrba54IDKW6bFcLVPm9l1E3/Iv5fP77r8tmDkw/KaJq74goXfqtZdjjNZ3dS4DfqisZelpeo8vcf6ir3LxP+Zd2dyZ8/2hlXaDRZCCGXk57P2f6a8830WrfNCpaOMNDW28oKmq32mV+b47Zv0o7bn3t/LzuTfCz4B6/gH7zq2mv0Rp3bvkmLz8z/6naMR+yU5T8GP2sqoWmK1gFCiGidCT+/kGVKA/brhtScvxs3bvj7+7u6usrl8m+//dZoNBJC7t696+3t7ebm5urqSutAVlYWdbKuri4yMnL69OkeHh4//vgjNd64cWPevHlUTq6urp46dWpeXp4QFCwgAAIgAAIgAAIgAAJvhQCUv0EPiXEBCIAACIAACLxLBKD8vUuljXsFARB4hwlMeOUvOTlZpVIpFIqSkhKujCel/D158kSpVHJj8sJM7mIj+aTShMvp59z2TQo/v/Bh0V2mylAVZ+o3fz74cM/dxzcOPNil79c1dzfOPvSB/Du300lHV1z40G3fpDuPbSttTt//1+U/Lth+a6NtAznF3vnHZn92dS3LQipgR/mzWq3Hjh177733uru7e3t7XVxcnj59StNZs2bNqVOnWJqic/7++te/njp1ymAwXL9+3dXVlapEcXFxcrm8trbWYDBs3rx55cqVNJFly5YFBwfr9XqLxbJ8+fKzZ8+yxIWBjt7+f1l3Jy6l2mS2nnlU9qfwW0z5I4QI9/nTG83/c9VvyUW27RU7df2Zz1ppmrviCv/fNb89b7IJfucTKubueC3giSp/11Jr8irbTWZrY0ffrG0J39+1iXA9feb/FXGnqLqTprk4NvXwnVfinNBzQojRZHxYdPe48hB3nz+q/H31W8zSs4FTv/nzpbQzbvsmXck4T5U/t32TDj36+pfMC9O++cui036EEKk6wJQ/Xp1Jr0h5WHR32jd/8T48/WHR3YdFd5u7G0Xdo0Yp5e+3334rKCgwmUzNzc3z58/n1gHhap9Go9HLy+vgwYNGo7G+vt7Hx+f+/fs0/a1bt27ZssVoNIaEhFy8eNGOJzgFAiAAAiAAAiAAAiAwygSg/L3Dg3vcOgiAAAiAAAgMTADK38CMEAMEQAAEJgCBCa/8/eMf/zCbzZWVlT09PVwNT0r548YRDQuVP0JIZUuZcLVPqvztvb+dO9qnGuGt3KuEkNbelqnf/Dn8vG3S3vT9fz2qPJjw5KHbvknlzaWf/xq5/Mdg7oWiYVHl74MPPpgxY4aLi4u3t7dS+UoP27Jly/79+22Ztrb++7//+4sXL1iCosrf3/72N7PZttme0WicNGlSTU0NISQsLIzJRc+fP580aVJXVxchZNmyZWxO2JEjR7Zs2cISFwZuZ9S6fPaA2q1WMumT+/aVP53B/P+tuXMuvrxL92pFU3rtrrjCRYdSaVhvNP8p/Bab9ieq/HE9OXT7afjRDGr55Ez2jl8KbIJcl+F/rvqtrk3PjSkazqjQCJU/TVniwYd75N+5EULmHHI9mvAtVf48v5tqsdrmF67/eYXbvkn1HbVSdYApf7w6Q31w7mqfJ06c+OST14vTCpU/lUo1bdo0i8XmOSHkwoULLH5fX19AQEBoaGhUVBQ9i39BAARAAARAAARAAATGCAEofxNgkI5bAAEQAAEQAIGRIwDlb+TYImUQAAEQGEMEJrzyR9W7//7v/6YaGBPzRk35u5JxnvsW4ODDPW77JuVUZVKjR+wU7+9lr5S/hIOqp4/c9k2qbCnbfP2TJWcDuBeKhkWVv71797a2ttJ1O9lVWVlZMpnMbDZfvHhx1apVzE51u+vXbfMO2Yeu9skOJ02aVFZmW2Nz3rx5N2/epPaenp5JkyaVl5fTFK5etWmZhJATJ05s2LCBhkX/PaMon7cniZ2as11pX/kjhKiLm5cdTvvXj++6f5nwKK+BXrsrrjDytJal878i7qSVtNBDUeUvraTlw4OaKTEK188f/d/Ie0u+e6UappW0/CXqvtliPf2o/MODGpagnYCE8pcU+2iv1+FphBCP2Mmxir1U+aPz/Aghu+5scds3qag+X6oOMOWPV2eoJ8NX/rRa7apVqzw9PT08PNzc3CIiItg9CpW/K1euvPfee/P++Mjl8hUrVrD4V65cmTRpElsXlNkRAAEQAAEQAAEQAAEQeLsEoPyNocE2XAEBEAABEACBsUcAyt/YKxN4BAIgAAIjQOAdUf7++c9/JiQkdHd3j77y90vmBe7gnzvfq6239Y05f28qf4vP+HMvFA2LKn9snz/eJV5eXomJiUFBQWzZRhph+fLlDip/dub8Oa78/ZZZN21LPPPtbxseDKj80cgWq2110H/9+C493BVXGPRNCg136vr/FH6rvKGHHrZ2G/8Ufquj9/Ucwb5+26qeN9NrrVZblIO3niyOfaX8EULcNisUjxvm7lDdyqijKdj/1yHl79Er5W/OIde+ftvuiSsvhArn/HHrAFP+eHWGOjPjwN8Cj3vYd4yeFV3t02AwuLi43Lt3z/oSwbFjx9asWcNSO3bsWExMDDskhKhUqnnz5nEtLFxVVTVt2rTY2FgvL6+enlfM2VkEQAAEQAAEQAAEQAAE3iIBKH8jMGhGkiAAAiAAAiAwcQhA+Zs4ZYk7AQEQAAE7BCaw8tfS0tLT0/Of//mff//730tLS5VK5T/+8Y8Blb/KysrMzEwWTRgY7GqfPBWnseuF+8H3Pb+bejrpKJWCbuf9Kjrnz77yZ7FYjEbjiRMnQkJCjEZjf/8rlSssLExK+Tt16lRgYODkyZMNBgP3ZcTnn3++Z88erkVqzt8vv/zC3ecvPDycXrVs2TI7yt/SpUt37NjB0u/S9f/rurtZZW2EkPjHDQPu89fR2/8g54XeaFt69KKq8v2ND2lSu+IK/8eK28lFzSazdVdc4ewvE1gWhJC/RN2/m/Vaxuvo7f9/VtyqeCkNtvUYp22J5yp/h++UzN2h/NeP7/b123Kx8ymse3y/4PZR5UG3fZM++WXl/YLbyqcP6T5/mrI35/z9ofxN/ebPkT+H7/zNNuEv9LQvIUSqDthX/oJ/8Jq+/68/Z1y4X3C7sev1Yq1Cb6nyZ+R8LBZLZ2fnn//85+fPnxNC2tvbfXx8uMrftWvXFixYwGoRIcRgMHh6ep49e9ZgMJjN5uLiYjrDjy71efnyZULIl19+yZYAFboBCwiAAAiAAAiAAAiAwOgTgPJnZ/CLUyAAAiAAAiAAAlD+UAdAAARA4J0gMIGVv+bm5vT0dKVSmZiYmJOTo9fruTKe1GqfT548USqV3Ji88DCVP0JIQV3emktL5hxyXXjKJy7rJ/o6wLbP32Dm/J07d24S57No0SKajh3lr6Gh4S9/+QtXhKOXPH36NDAwcObMmbNnz6ZrhEopf2az+ciRI3PmzJk6dWpkZGRjYyNNwb7y5+7uvnbtWhqT/qt50iLfqfL7OjnytHbG1ng65++ett7180eumx79KfzW+xsfun7+KC6lmhDS1mNcsD/l/0Te+7+R9+btSaKSoW3xzLjCFccyQg9p/vfau/P3Jpe9eGPy2YPcF+9vfPi/1979+loRzfSSqnLG1vjgAykrj2duu5LPVf7q2/T/Y8XtTRdyuU6Khg882OW2bxL3b/6x2faVv2XnAg8+3ON+8P3lPwaXNj6lyYrWAfvKX8KTh0EnPKbv/6vbvknJpa+2bxR18vr165yqYQvS3Rnj4uJ8fX3Dw8Ojo6P37t3LVf56enpWr149Y8aM2bNnZ2S82gGxpqYmKipqxowZkydPDg0NTU5OJoRs2bIlMjKS5tvX1zd//vzz599Yz1bUJRhBAARAAARAAARAAARGhwCUv3diGI+bBAEQAAEQAIGhEoDyN1RyuA4EQAAExhWBCaP89fT0JCcnp6WldXZ28rQ64WFdXV1aWlpSkm23OeFZ+xZR5W90hvHDzMVgMLi6uubk5AwznTFy+a64wuhzzrmXvn7zv6y7k/ms1bm3Rvf5++hckHOTRWogAAIgAAIgAAIgAAIgIEUAyt+4Go7DWRAAARAAARAYbQJQ/kabOPIDARAAgbdCYMIof/blOieeHb/K3/nz5/39B947UOolwlizO1H5O/mgzP3NxUKdcrNQ/pyCEYmAAAiAAAiAAAiAAAg4TgDK31sZViNTEAABEAABEBgvBKD8jZeSgp8gAAIgMCwCUP4GKwqOR+Wvq6vL1dXVz88vPz/f8bcGYzymU5S/Tl3/v6y7M3NrfE5Fu9PvF8qf05EiQRAAARAAARAAARAAAfsEoPwNa3iMi0EABEAABEBgohOA8jfRSxj3BwIgAAIvCUD5exeUP/tvB3AWBEAABEAABEAABEAABEBgYhCA8oeBPgiAAAiAAAiAgB0CUP7swMEpEAABEJg4BKD8QfmbGO84cBcgAAIgAAIgAAIgAAIgAAJQ/ibOWB13AgIgAAIgAAIjQADK3whARZIgAAIgMPYIQPmD8of3IyAAAiAAAiAAAiAAAiAAAhODAJS/sTfmhkcgAAIgAAIgMIYIQPkbQ4UBV0AABEBg5AhA+YPyNzHeceAuQAAEQAAEQAAEQAAEQAAEoPyN3NgZKYMACIAACIDABCAA5W8CFCJuAQRAAAQGJgDlb7wrf5cuXdqxY8fbfceRGRFWd/e2U3ww63UKmYuhucnB1CwGQ86mT5L85U9j9zt4yViOpo1em+QvL/n+27HsJHwDARAAARAAARAAARAYswSg/A08BkYMEAABEAABEHiHCUD5e4cLH7cOAiDwLhGA8jd85W/z5s2bNm0a1OD/6NGjmzdvHtQlopG7u7vd3NwaGhpEz3KNhuYmhcyFEJK/Pabq2s/sVIPid23UGkJIou/s7rJSe3aLRRMa0JDwiMVhAScqf1aTqebGVXOfniVuP9CckpQUILf099uPNo7O9jU22LTP1pZx5DNcBQEQAAEQAAEQAAEQGCMEoPy9S6N53CsIgAAIgAAIDJoAlL9BI8MFIAACIDAeCUD5G9fK38WLF9euXevIWwYnKH+E1N25mRa+SJidE5U/YeL2LfX3bmesWmo/zrg7mzDHraf82bhzGw6DAAiAAAiAAAiAAAi8dQJQ/sbjqBw+gwAIgAAIgMCoEYDyN2qokREIgAAIvE0CUP5GTvnbt2+fh4eHq6vr/Pnzb9y4Qd8C3L1719vb283NzdXV1fvlJysri57KzMwMDQ2dPHmyv79/SkoKNW7ZsiUmJoaGHzx4MHfu3M7OTnpICFm6dOlPP/3EDmkgNyb62aljBV99kbLQLylA3p6bTQhxivJnNfUnB3m3pGl4OWZGhJUe/06zZIHKe1b+js2mnm4awazXlRw5qA6el+g3t2jfTrP+1Uy+9tzs1I9CVJ6ywr070lcsblD8TuNro9akhPrzVvtsy85M8pdX/vRjxqql6uB5Lx7e5+Ze+9uNjDUfcS1SmfZ3tOdt2aD0mpG+csmTg3tzY6IJIVazWSFzqY67krUuXB087+nhAzQpU1dX3pYNiX5zVd6zstaFdxYVsCyq4i7nbFxffu4HTWhAkr/8+ZWL9JSovf7e7dSPQpSespSFfqXHv6NzE2t/u5G2/EOWYEP8g5RQf3ZICFF6TOsufcq1IAwCIAACIAACIAACIAACjhCA8vc2R9fIGwRAAARAAATGPAEof2O+iOAgCIAACDiDAJS/kVP+zp8/X1NTQwgpKCh47733cnJy2FhduNpnRUXFe++99+jRI4vFotVqXV1d6+rqCCF6vX7+/PnXr1+vqamZNm3a48ePWSKEkPfeey8tLY1rIYTkxkQn+s7uyM8jhJj1erpupLmvj27F156T1fu8gl2ir6ulSl6D4ndTd9eA9qq4K1mRK1k0GsiMCFMHz9PX15n1em302qL9u6m9cPc2bfTa/s4Os173eNumJwf3EkJMvT1Kr5l1d29ZzeaaW9cUMhem/L10mL/PX1t2pi1O/ENCSJs2U+kpY2t7Ws3mgl1bC3Z+wfVHNFO6zOnjLz839/X1VlaofNy5yt+TQ/sIIf2dnUqvmVTkM7a21ty42t/ZSSyWmhtXlV4z2AKkVXGXlR7TquKu2DK1WnW11TR3UfuLB/e6nhRZTSZDa0vqspDKS+ds96jT2bS9ZyX0wpyN6ysu2uzsk7o0+PnPl9ghAiAAAiAAAiAAAiAAAiDgIAEof84YJSMNEAABEAABEJiwBKD8TdiixY2BAAiAAJcAlL+RU/64g/OwsDDu5Dyh8nfgwIGoqCh2yccff8ziV1ZWymQyf39/ZqHRjEbjv/3bvxUWFrKraCA3Jrpo306e0VmH5j59ou/s9sevVUxCSGZEWPm5kzSLljSN0mumTd/q7VXIXNiqlV0lT6i9QflIvcCH+ZPoN3dA5U/pMY3Gt5pMCpmLvq6WENKcqlZ6TEua76Grs8mr9COVKbFY4t0ndxTm02jFB/Zwlb/O4lcMsz5eUX/v9h+J/fG/xRI/y5VtglgVdznlw/l/nHv9v5SdxSg/fzpv60Z6WLhne8nRWEKIsa013n1KX+MbOzW252QpPaYpvWbqal7JiiwRBEAABEAABEAABEAABEDADgEof9zRLsIgAAIgAAIgAAI8AlD+eEBwCAIgAAITkwCUv5FT/n799dcPP/xQLpd7eHi4uLj8+OOPbIguVP6io6OnTp0674/P7Nmzjx07xuJHR0e7urr29PQwCw1Izfmjc8t4kZ11WHHxbM7G9dzUMiPCam5do5bu0hKFzMXS399TUaaQuaQuCdLQv8WBib6zzXpd1bWfuetzpi3/cEDlL8lfzrJTyFx6K1/NWbSa+nNjoou//ZqdlcrU2NZqkwzrbdMoCSHl537gKn+66ipq10atqblxlRBi6e8vPfF96tJgdYivOsRXMeN9pg5WxV3O/nQdjc/9V9TenpeTvWFdyofz1SG+Kh/3nE2f0Evac7MT/eZazebquCvZG/ipZa4NKzt9nJs4wiAAAiAAAiAAAiAAAiDgCAEofxNz3I67AgEQAAEQAAEnEYDy5ySQSAYEQAAExjYBKH8jpPxptVo3N7fS0lI6Pl++fPm5c69XdDx27BjbvY9GOHDgwM6d4hP17t+/7+XlFRMT8+mnn/JG+1L7/LHN53jxnXJo6ulWesq6S18tVimc86fycaereipkLsbWVl6mQ5jzJ6X8EUJqbl7LWhfOsjD19ohmajWb42e5Ss35Eyp/FRfOZK4N6+9ot63oaeqPn+XaWfxqqz+6nx/LkQWEdovBoPSY1hD/gFitVG7kKqYpof7Nqeq08EV0IVOWjm2fP08ZExq5doRBAARAAARAAARAAARAwD4BKH9je/wN70AABEAABEDgLROA8veWCwDZgwAIgMDoEIDy5xTl77PPPjNyPoSQhIQEuVze399P9/n729/+xlX+rl27tmDBAnqWDt2fPXs2efJktVptNpsNBkNKSkpVlW0iWkVFhZubW2FhYV9fn7+//8WLF7lD/YsXL65du5Zrofv8jajyRwgpPXkkf8dmlu/Lff586T5/2Z+uo9vm2W585xf522OM7W22DQtf1DeqFGyfv/r7vxGrte7OTcWM94c8548QUnf3dsaqpcwTqUwJIY+3bXq1z99z/j5/QuWv5Mihwt3baLJVV39WyFyGoPyZuroUM96nK3b2d3ZoFgVylb+Ki+fSwkKVXjMtBgPXf1vlmePGFhflncIhCIAACIAACIAACIAACNghAOVvdMbRyAUEQAAEQAAExikBKH/jtODgNgiAAAgMjgCUP6cof5Pe/OTk5Fgslp07d/r5+a1atWr37t3h4eFc5a+np2f16tUzZsyYPXt2RkYGHbpnZGQsWbJkypQpU6dOjYiIqK6u1uv1fn5+TO2rqKiYPHlyXl4eG+p3d3e7ubk1NLyxS1xuTPRIK3/Gtlalx3S2C11mRFjpicOpS4NV3rMKvvrC3NtLPTTr9SVHY20LXXrKUpcEVf1yidrbc7NTl4UovWYU7duZvmIxnfTWmJhgW1oz2Fchc1Ev8FGH+NrUQULasjPtzPmrv/9b+srFDIhtf0GJTI3tbbkx0UqvGekrlzw5tM/+ap+G1pbsT9elr1yS81lk1dWflXLZEJQ/QkjtrV81SxZooyIeb9v09PABrvLX19SomPlB8YE9XOdpON59Sk9FudAOCwiAAAiAAAiAAAiAAAjYJwDlb3DjYcQGARAAARAAgXeMAJS/d6zAcbsgAALvKgEof8NX/uyPvUf67KVLl7Zv3z7SuQjTfxq7v+ibXUL7YC3qYN/23OzBXsXit2alq3zcTd1dzOJIoPLSOar8ORJ5hOLY1gL1lHXkv9ZxaUbdZaWKGe/3d3aOUL5IFgRAAARAAARAAARAYAITgPL3ro7scd8gAAIgAAIg4BABKH8OYUIkEAABEBjvBKD8jXfl7229tuhraqy8fJ7uYDdYH9qyMvo7OwghzSlJiX5zzXr9YFNg8a0mU9G+nepg36ex+5lxwMBYUP6qfrmU+lEIz1Vt9FpNaIANLD4gAAIgAAIgAAIgAAIgMHgCUP7G+wgd/oMACIAACIDAiBKA8jeieJE4CIAACIwVAlD+oPwN/n3CcK+ouHAm0W9uot/cjNXLhJPehpu6A9e/XeXP1N2l9JSlLg1mK4g64DKigAAIgAAIgAAIgAAIgMDABKD8jZWRNvwAARAAARAAgTFJAMrfmCwWOAUCIAACziYA5Q/K38DvDxADBEAABEAABEAABEAABEBgPBCA8ufsETPSAwEQAAEQAIEJRQDK34QqTtwMCIAACEgRgPIH5W88vMGAjyAAAiAAAiAAAiAAAiAAAgMTgPInNfKFHQRAAARAAARAwGAwQPlDNQABEACBd4IAlD8ofwO/P0AMEAABEAABEAABEAABEACB8UAAyt87MYzHTYIACIAACIDAUAlA+RsqOVwHAiAAAuOKAJQ/KH/j4Q0GfAQBEAABEAABEAABEAABEBiYAJS/cTUch7MgAAIgAAIgMNoEoPyNNnHkBwIgAAJvhQCUvzGi/LVmpiUHeQuH8gW7v1SH+Ma7T25SJwrPjqjFrNcpZC6G5qYRzWWUE++tqkwLC00O8Hzx8P4oZJ0VubL29nVeRhajUSFz0dXV8OzssP7e7aQAudJr5vMrF5mREPLshyNJAfL0FYu5RmG4OVWdHOiVuiyk+1kJ92zZmRNJ/nJtVIRZr+fax2BYisAYdHWYLnU9KdIsWaD0mpkbEz3MpISXWwyGnE2fJPnLn8buF54dZUtLWoomNMCRTDWhAeoFPgqZi6m3x5H4Towzyv1D2dmTBTu/EPqfGRFWd/e20E4tUq2jUaVQh/iqF/joaqqlriWESPUPUnb7/YaDmdrxx4mnMlYtbVD8PmCCNTeuqkN8VZ6ykqOxA0a2E8E+GTsXjv4pqTrjFE9GtNUI+w2pikrvxXFntNFrk/zlJd9/6xQIg0pklFvN0L6HPDm0TzXPXek1syM/j92dnWcKL6ZU63iL2NldvCMBKH9vZViNTEEABEAABEBgvBCA8jdeSgp+ggAIgMCwCED5G6byp6+rVXpM62tqHOarBCnljyarCQ0YjvJX/+Bu6tJgKQ+zIleKvmW2mkw1N66a+0ZJJSrc+9WTQ/uknHSWvfRY7ONtm1hq9smwaI4ErGazUM8byhs3i0Upl3UU5vMyNff2KmQuPeXPmD03Jlohc1HIXJSeMm3UGp7OV/TNruJvv2aRacBqMqUuCWqIf8izO37olGIaoNVIEHDcSamY7blabVSEylMWP8tVKg6zO6duWCya0ICGhEcsWV4gZ+P6ysvneUZnHTanJCUFyC39/a8SHMgZp+Qr1Z/oG144ospQHwzNTTzlzznFMdAd8vqHASrqQKnxzgvJDEX5k0hb/aoAACAASURBVG4d6SsWV//6C8u0PS+H9g/s3/oHd9lZ0f6BECJqt9Nv8DIdhWJqy84U/ZUMIaRRpbCverLbJ4QUH9jtuPInlakdMty8aLgpWaUJDVB6zdQsCbIYjcIIQ7YMUFGl68yQc+ReyGs17JSupjphjlve1o3UMrS6IdVviFZUQoiUM8wrbqCvscH286bWFmZ0ygOOpSYV4LUaJ2YqWlGH8D2ks7gg0Xe2Wafj3QL/mcI5XXf3lrG1lWMgUq1DiJ17FTcsTmZUHmRcN8ZpGMrfsIbHuBgEQAAEQAAEJjoBKH8TvYRxfyAAAiDwkgCUv2Eqf4SQwt3bSo4cHOargRFV/qxmszrEtylZJeqk8H20aLSRNuqqq5Qe03hvjpyeaeGe7aXHD7Nk7ZNh0RwJOEv5M7a1KmQuZj3/jZu+rpZnz42JfnJwr9VsNvf2lp74nvc2/PmVi4+3vtY42S3kbFzPlQeY3cGAs4rJTquRIuCgh3aidRYXNMQ/rLl1zRHlz1l1o+7OzbTwRVJeaZYEtaSlSJ0dpr3+3u2MVUu5idh3hhtzyGGn9CdC5c9ZxWH/vnj9g7O6d5qpkMwQlD87rUO9wIdbl6jyZ+7ttRiN9I9YLOz2pfoHKbtUv8HLdBSKSVTbYPfleMApyh8hRIqM0JNE3zn0Fzy6mmqr2SyMMBzLW+lRqcPCVmOzW63a9aszI8KY8ufcuiFVUcWdkSabMMeN+3saZz3gpDO0neG1GidmKto6hqD8NSQ84j076B0Jnyn271SqdfCwSyUiRWYUHmRSLo0jO5Q/DPRBAARAAARAAATsEIDyZwcOToEACIDAxCEA5W/4yl9vZYVSLuvv7OC+EaA6UHXclax14ergeU8PH2BnS44cpEuNpS4Lqb/3akk3qvyVnjyi9JRpFgU2qhQsPiFEOOevs6ggK3KlyntWkr/88dZN3B+tcy9k4ZobVzNWL2OHNFDy/bea0ICEuVMT/eZqQgM0oQHmvj56Shu1JiXUn7vap6m3RyFzyd+xJclfXhV3JWWhX/rKxXQ5PrNeZ7up4HmJfnOL9u1ki0maerofb9uU6DtH5eOeGRFmaGnmOcA7zN8eU3rie57x8dZNZWdPMmPelg3lP56ihzU3r2mWBCm9ZmqjInS1rxe4a8vKyIwIU3rNTA70qoq7zK4lhBTs2lp68gjXIkomLXxRbkx0ot/csjMntOtXJ/nLu54WE0KksGes+UgTGqCQuaiDfTWhAUxyy4pc+ezUsayPVyg9pmdvWGfq6SaE0NU+K3/6MSlAnuQvLztzglitNpde/pI9ZaGfQuaSEuqvCQ2o/vU/mKu6mmqb8vdHARFCbMrfH7Mku5+VKGQuRs4v7qt+uZS3+VN2OQvkfh5VHXeFHQ4hIFpMg01HtNXYIdBV8iRhjltjYkLqshD1Ah+6Nqapqytvy4ZEv7kq71lZ68I7iwqYG7qa6rwtG5Lme6jmuRd89caCii1pKULlT7TOiNYNloWDAaupPznIuyVNw4tfsPMLTWhAvPuU5ABPTWhAwa5tLIJSLqu/d9vWdYT4qkN86cQL0X6DEGLu7X16+IA6xFfpNUO7fnVfYwNLp/a3GxlrPmKHtrfxEs5krFpatG+ndv3qtPBFhbu3sakeUpkSQoROSvUnhpZmTWgAvU2uM/X3bqd+FKL0lKUs9Cs9/t3ruYmECJU/QohocdjpH9pztZkRy5VeM1M/CmnNSGVZ26kbwv5BtKKWHI3VRq1JDvR6vG1T8bdfJ/rOrr31KyFEqkJKkSk7e/Lxtk2Fe7YrPaZrlixg03YzI8JKj3+nWbJA5T0rf8dm2m/YaR301pIC5C3pr6sZVf6k5pZJ9Q9Sdql+g5epVDG1pKUkB3gWf/t11rrwtLDQZk0y9VmqRyWEVMVdztm4vvzcD5rQgCR/+fMrF3W11baKFOgVP8uVPrDYesjPfjhie5bNcePOK5UqDpq1g8qfnUxpOlJk6Fnuvykfzm/NSudanBgWrah26oxoj2qnOAbVaggh1b/+8vS7/U8PH2DK32DrhlS/QaFJVVRhEyZWa/Wvv6QuDVZ5ylKXBrdlZXCxKz2mdZc+5VqEDzir2ZzoN7ctO5NGs5pMib6z23Ozbd2vxJcfQojoM4WmIGw1wkwJIYP6HmKnog7qe0hHYT5tcQlz3Ggr6ywuZHyEzxSbn2Ghtu8/Mz/grgtKL5FqHULsLAteQJSM1IOMd+07fgjlb+KM1XEnIAACIAACIDACBKD8jQBUJAkCIAACY48AlL/hK3+EkLwtG2z6DedDlT8qzPR3diq9ZjJZouqXS/q6WpuMVFyYMHcqfVfSmpmmkLlUXDhjNZla0jTx7lP0L+pZekLlrz0vpzklydyntxgMBbu2ZX+6jkUWDViMxiR/eZv21asrbhzhTBR6lrfPH1X+dNXPy388lfLhfKupX7t+NVUoC3dv00av7e/sMOt1j7dtenJwL02h7MyJ7E/XWQwGYrF0FheYurq4+QrD3aUlSk/Zq9fcf5xuSlKmhPrTI1N3V8LsKVTkq7tzMznIu6eizGo2V/1yKXVZCJ3R0vW0OGHu1KYkpdVs7u/s4Gqopt4ezaJA3sZ7omTSwhfV3vq1PTebLuBZfu4k3SnNDnapOX+axYG62ur+zs605R8+v3KBKX85mz4x63W6uhrbpoOPXm86SDUP4Zy/mpvXkvzlf1Cx/c9V/iounEkO8ubOI7HtJLTAp7+zk3sJIeRp7P68Lz6zmv5YAZJ32oFD0WJy4Dp+FGGroTFECXSVPFHM/KDw6+1UydBVVxFCjK2tNTeu2u7RYqm5cVXpNYMuTmvW65ODvJ+dOmbu05v79PW/3+HmLVT+pOqMaN3gJuVguCruSlbkStHImtAA7jwtGkcpl2WsWkq32NQ3vKCSmGi/QTufnI3rja2tVrO5PSeL7R9pNZsLdm0VbiMn6kzGqqVpyz+kunL+js1sErNUplT5EzpJCJHqT4T7db14cK/rSZHVZDK0tqQuC6m8dI4hElX+RItDqn/orapMmDu1MTGBWCzteTlKTxntUe3UDdH+QbR7LzkaW/DVF2a9TimX1d293Z6TRZdTlqqQ9L6EZMrOnkyYO7UtK8NiNBbt25nzWSSNmRkRpg6ep6+vM+v12ui1Rft388gI+4eeijLFzA901c9ZTPvKn1T/IGUX7TeEmdL+TfisaUlLUchcqCzXU/5M6TGd/lrFTo9aFXdZ6TGtiv5MwWplv+0QndVE75q3z5/94nBQ+aMp28lUlAwrBW6gaP/u1I9CRm4B7eH3qFLFMdhWo39Rb/sh0csfJXCVP9EmLFU3KDphv0HtohVVtAlXv/yhUndpCbFaddXPqWLHyiV1afDzny+xQ0KI6AOu5Ptvi77ZxVxSL/Chv9eR+vIj9UwhhIi2GtFMh/A9RLSiZkWuHOz3kAbF78I5f1LPFIqFt88fNUq1DiF2bhFww6JkXv4yQPKpyr38XQ5D+Rt7Y254BAIgAAIgAAJjiACUvzFUGHAFBEAABEaOAJQ/pyh/ncWFSq+ZbKKMbW7Ny13f2G+lsz5ewab3cd9EaKPWVF37mRDSmpkW7z6Zzc/IWL2M2mlkofLHTcT2XttrJtciGn5+5aI2KkJ4Svg+msYRVf6IxdKg+J0KjUX7dlb/+gtv/7mukifMmfJzJ9NXLrEtpUXntAnzFlhyNq6vuHiWa7b096u8Z3UW26Zz1f52IzNiOT37xk45VqvSU9ZdVvpy96Y9hXu2c1Og4bLTx+NnuWauDbOaTLyzQjJp4Yvac7IMzU3x7pMJIS8e3GPT+Ni1POxSyl/FxVd6xrNTR6ljdM5fe04WTar0xPfcd6NC3au/s0Pl4x7vPpm3XmtuTLTSY1qSv1wplyX6zW3Pz2W+2QJWa87G9YqZH7B5gfSssbVVHeKbMMftxcPXcuMbFzpwICwmBy7iRxG2GhpDSIAQYlP+ZC59jS/4qbBjiyV+liutAw3xD9TBvlK1Tqj8FR8QrzOEEGHdYBk6HjD36W1zRB7nCC+RUv5ePLgnjMwsrN8wtDQrZC70lwTsLCGkOVVtqxvzPZgQyM6KOpOxaimVpW19UUZqUsAbGjO9lmVKD5VymaiTUv2J1Bt8mlr5+dPCVkCnFDPPRYtDqn+wbffFWe02Nyaa9qhSdcNO/yCsqCVHY8vP2SYia0IDOvLz+hpfqLxncf20hTkVkp4Skik7e1IbvZaebc1Ms8kJLz+ZEWE0fUJIS5qG9ajkj9mQPOVPG7lKIXMpPfF6HWNCCFX+En1ns7/eygqavu1fif5Byi7sN0QzpekLW01LWorSYxprkpkRy2t/u/HamZchXo9aFXc55cP5vDi2qVTS+/zxlL83rhUUh7OUPyGZN/L946Dypx/zNn9acuRQ/vYYais9cVhYw+mp3soKVmoswFroH0ny/xdWVBpjaD0qtzgG22qyP11Hd5PlzfkTbcL264ZkvyGowFJNWLMoUPTbF4XTnpOl9Jim9JrJ3SFS+ICjbOmPMAp2bX32g23lADtffqSeKXZajTDTIXwPEW0dWZErB/s9RKj82XmmUJKiyp9U6xDFzq/QfxwLydjgSz9V/7juXf8fyt/IjZ2RMgiAAAiAAAhMAAJQ/iZAIeIWQAAEQGBgAlD+nKL8EUK0URFs5TGm/NGZSS/Prqm5cZW+h6i7czNj9bKUhX62Bfo8ptHfm7dmpiX6zWUvKvK2bHh26hg7FCp/fY0vCndv0ywKVIf4Jgd4JsydyiJLBcw6HZPQuHGE76PpWXHlj5CGhEc5G9e/1Nh2V8ddsf2AXeaSuiRIQ/8WByb6zqYvps16fenJI6lLg5WessI923lvq7k+sHD74xzb5X16ZqFiHp2EpP1kdfX1OHpK5eOuXuDzKtMlQUnzPehCatmffVx+/jT3chY2trclB3nTN5LMaHuFJCBje+OWl2Nsa02Y40YIaVD8TlfOtINdSvljUwzLz5+m73yp8tdbVUl9qIq7krk2jPkj+paWEFJ5+bxmcSCLRuf8Fe7dYWxr1dfX1dy4qprnzhXGWrPSE33n0Hlj3KuenTqmjYqwTcR04BM/y1Uhc1HIXOj2VOwK0WJiZx0P8FoNvVCUQFfJE6rCchO39PeXnvg+dWkwXRVTMeN9qrVXXj6vjVrDjckNC5U/O3VGWDe4STkerrh4lrYa3iVSyp9w2TTRfqOjMF8x430mqHATt5r6c2Oii7/9mmukYaEzGauW1t25Sc92PSlSzPyAhkUzpaeUcpnQyUHN+WvPy8nesC7lw/m21Y993HM2fUJTZvqWUBcRLY7iA3uE/cPjbZtU89xZ/5Ac5F1+7gfajqTqhlT/IOzebcrfy05GsySos7jA0Nyk8pTZxD6JCknvS9jTcvf5a8+zdX00ZmZEWM2tazTcXWpbyJcthSraOgghHfl58e6TuWu9UuVPX1draG6if9wfPUj1D1J20X5DmCn1WVhMdLVPetbWd30eVXHhDCHETo9aFXdZdC67qLZBU+Ypf/aLw1nKnygZdqc0YDEYlB7TDC3NVrNZG7mKyjCJvrO5s7S5l9gmwv5RaizA/WkRNzI3PMweVao47PSowlZTf/+37M8+pl4JlT/H6wZNQUr5E62oQmcIIQmzp7TnifzqgqafuTas7PRxLkObai72PUSzOLApWWXu0ys9pvdUlL+avSfx5cfOM0Wq1QgzHcL3ENHWwd3nz8HvIULlz/a1VvqZYpsF7jVT+ESQah2i2HmlwA6FZOgp4YOMXYKA7QdAzc2DGuCYXn60A31otPz8/PLy8rq6upaWlvb29u7u7p6eHp1Op9frhePKgceiiAECIAACIAACIDDqBKD8jTpyZAgCIAACb4OAcISm1+t1Ol1PT093d3d7e3tLS0tdXV15eXl+fv6gxpATNXJzs/hmdW3ZmUn+cjZp75UO9HJNQq7y156Xo/Jxt02De/nRrl9N9ULhnD/uHm+pS4ObkpTcdxnaqDVPDx+g+k17rpYKVNwIouGysyfzvviMd0q7fnXd3Vs8I93ARrjPn00G4yh/VXGX6Sqg3B3mhEn1NTVqlix4tW6b8PSbFm3kqqqrtnmQ7NOel5PkL9c3vEiYPaW/o53a01csFmp4dub80avyd2wWvuYjhPDICN+40Y3l7GG3WGxLg3K2G6QqiJTyx53z93jbJnazUm/2e59XKGQu3FU6uat9EkLUIb5MLaBrYXGlFJZ+3pYNvMXN2KlBBYTFNKjLaWReq6FGUQJ0VypeFhUXzmSuDaNVwmrqj5/lSueGSs1QoZcLlT+p+Rk0Pq9u8Hxw8NDU022bllpawosvpfzRG2GRpfoNqTl/9MKam9ey1oWzRFhA6EzGqqVUGCOENCWr6LqyUpnSdJRyGc9JapfqT3hv8KkW0hD/gMqW5ed+4Cqj/R3tCpmL6PrAwuIQ7R9Kj8WyZYfZjdu6L7vzQaX6B15FFSp/SrlN+ZOqkFJk7Ch/3Dl/Kh93dguirYOeTfSdw93DzP5qn1VxV0T7Bym7VL/By5T5ySumlrSUhNlT2PMxbfmHtGO006PSff5YgizQnqtNDvRih9wAT/mzXxxPY/eXfP8t93I7YTuZSpHhpmbq6rLV594em6rd2pIUIC//8ZT2k9XcONxwT0W50msm76/ypx+5cUTDvIpK44jWGdEeVao4BtVqig/spr8XYf/S1sEcdrBu0Pi8foMlIlVRhU3Y/pw/paeMrc3AErd9ZxN8D6m4cCZ/e0yD4ve0sFAa086XH/vPFKlWw8t0CN9DRCuqHeVP6nuIqPJn26lR4pkipfxJtQ4p7Nwi4IZ5ZF7xl3iqci98l8NQ/t7GqBp5ggAIgAAIgMC4IQDlb9wUFRwFARAAgeEQgPI3WIVSSvkjhGRGLK+5+WqihpTy16RWpSz0o/qNbZ+/2VOY8vdqnz+zuSVdkzDHjTt7I397zNPDB7ivMNLCQukcHavJlL9js4PKn23HQbnsjTXfCCnYtZVuYsdN33HljxBSsPOL/O0xxvY2Qoj+RT3bWq81M40qYf2dnalLg+2suMXNuiVdY9uy7s2N6NTBvtmffZwbE8Vi1t6+nro0mN6Lqbur/vc7dP5E15OihDluTckqq9ls6uriKaYFu78sPf7Gmng0QR4ZqTdu9rEnBcjZvdNk7bxx4+7z15DwiN2X6FtaQoiurkYhc+HOm7Qpfwf3Ws1ms17XnKqOd5/M3cfx+ZWL3OUTWfo5G9dzF5Jl9sEGRIupURX/5NA+qYksollwWw2NIEpA9D11yZFDhbu30auqrv6skLlQLcqs0yUHepWdPk43wny9jaLVajEam9Sq+FmuFqORzaOyX2d4dYNm11P+7MmhfWzipuit8YylJ4/k79jMMzqo/En1G3Tq5+t9/vJyuCt/1t29LdyriTrAcyZj1dJXG8v19mrXr3763X6bBCjRWdEUpJQ/qf6E9wbfpoXMeJ+usNff2aFZFMhV/gghiX5zG1XxPFyEENHiEPYPVDtpSddYzWaLwdCakUr7Ism68TInqf6B171LKX9SFZLehZCMHeVPHexL9/nL/nQdd8Fe0dZB008O8ubuGUmVP3Nvr62qv/zjNkyp/kHKLtVv8DJl5cUrJrqXW/n501aTqUmdmDDHjU5HttOjSil/uprqePcphhaRn+DwlD/7xVFz42r6yiVMjGSeiwbsZCpFhpeOdv1q28xUi4UQUnf3lkLmYtuEUuJjNfXrG17w/oRTYEWvHk6PKlUcQ241wjl/wiYsVTfo3fH6DXbLUhVV2IRty8Yu9Ot+ZvvVha62mjf/L2GOG10jmqX8Kl/B9xB9Xa3SY5pNgvqPn1hkqS8/9p8pUq2G91QdwvcQ0Yo6hO8hUsqfnWeK6Jw/qdYhhZ2B5QV4ZNhZ3oOM2RHAnL/hDI1xLQiAAAiAAAi8CwSg/L0LpYx7BAEQAAEDlD8nKn9N6kR1iC99uyql/BGL5cnBvalLg7M/+/hJ7Ddsba7WzLTkIO9np44qPWWaRYFNahX3zYWuuip95WKlx3Q2g6c9PzctfFFW5MqczyKf/3zJQeWPEFJyNLZg95fcxLuflaSFhSYFyJODvM19fYSQxsQE2/KJwb4KmYt6gY86xLf+/m/05+3COX8vNUJ9ydFY25J9nrLUJUFVv1yi6dfcuJoS6q/0lCUHeJYcOcR978x1QBhOX7G47u5trr3s9HGFzIU3ya/m5rXUpcEqT1lyoJdtC72XL1XpRmUZaz5Ses1MDvDkvqQjhBR+vb30+HfclFmYS0bqjZt97A2K39XBvsmBXkyhtPPG7fmVC0kB8iR/2+QP5gNb55Cr8NGz+vo6m/Kn07HIuTHRdFKF0mNa6rIQtpwsjVD504+Pv/ycRWaB7A3r2IqpzDi0gLCYSr7/Nt59CndRwQFT5rYaGllU2xBV/gytLdmfrktfuSTns8iqqz9ztShddVVuTHSi31yVj3v+ji005dbMNDYNRSFz4W6f1pqRKlVnRFtNU5JSIXPhvUS2f7PGtlalx3TublJ0oziuWkNT4N7IqzQl+g1CiKm352nsfnXwPKWnLCtyJXfF1/r7v6WvXCzqFc+ZjFVLS08cTl0SpPKeVbDzC3Nvr+0q6UxtMzwk5vwJ+5PS44fVIb5J8z3i3SfTdVmpYlp761fNkgXaqIjH2zY9PXyAp/zZKsYCH6VcRrfU4t4Ft6lSu2j/0J6TlbUuXOU9SzXPtpQo2/JQtG7QdOz0D9yKKqX82amQhBAhGTvKn604lgbbiuOrP4rjpYuirYM6rw6e16xJpmG2zx+3wnOXQZbqH6TsUv0GL1OWO6/VtKSlqIN9S49/Z3vALQ5kqwfb6VGllD+aMn1gVV6y7aJqaG6i9Sph9pRE3znqEF+6yK394jD36fO++EzlKVPKZa8qPNd7QbjkaCw3U3ZeigyLQAPG9rbCPdvTli/URq3J2bj+yaF9acsX0gcuL+YwD7kVlSYlWmdEe1Q7xTG0ViOq/DlYN6T6DXpTUhVVpAlbLFVxVzRLgpRymWZJEHdeLCEk3n0KXbpTiF34gMtaF66Y+QFXdTbrxb/82P8eYqfVcDMd2vcQYUUdwvcQKeXPzjNFVPmTah12sAsLglq4ZFgc3oOM2RGA8ocRPgiAAAiAAAiAgH0CUP7s88FZEAABEJggBKD8OVH5I4SkfhTy4uH9sfzSwdDcpPSYrq+vG8tONqoUmkWBTMlzoqvPTh3L/nSdqAY5xsmY+/Tx7pPbc7MdomG1Pv7yc7r5GTe+Wa9XB89rSn5DV+ZGGFRYWEyZEcvpdLFBpTMeW82zH46kLV8ousGenXt/Gru/6JtddiI491RrVrrKx93U3SWaLNeZjFVL6x/cFY02Bo0j11Tt9A9jv3vPXBvG+xmBZNlJ9A9Ewm6n37CTKbeYbMpfiK+kP+P2hB0yb/GeRrlHtd9qRDkMt25IVFRCyKCc6S4rVcx4v7+zU9RJ4QNONNoQjHZazchlOgQ/hZfYeaYo5bKup8XcS6Rah33s3BS4YSky3AcZNz7CWO1zggzUcRsgAAIgAAIgMDIEoPyNDFekCgIgAAJjjACUP+cqf+35uQ2K38f4G4cXj+535OeNaSet1srL5+lycM71s6+xIXvDuuQgb1GBdoyTqbr6s2ZxYFr4IvtMmlPV6gU+2qg1bJITjV925oQ6eF7Brm0OLnBnPxfb2TeLydTbo/SaYWxrHfjCN2OMx1aTvnKxcK7em7clctTX1Fh5+fxg9UKRhBwzWU2mon071cG+osv5cp0ZX8ofIWSEmqr9/mGMV9S27Mz0lYvVC3x480p5lUWqf5Cy2+837GfKimlCKn/2yfCwj+bhKFdU+61G6saHXDekKirNyHFntNFrNaEBtg5Z6vPmA04q1hDs9lrNiGU6BD+Fl0g9UzoK8xPmuJl6utklUq1jYOwsCV5Aggz3Qca74h0/hPI3xgbccAcEQAAEQAAExhYBKH9jqzzgDQiAAAiMEAEof85V/t7xFw24fRAAgfFIYNwpf+MR8rvs84RU/t7lAnXivaNuOBHm6Cf17IcjSrks0W8u3Xl69B1AjlIEoPyN0MAZyYIACIAACIDAxCAA5W9ilCPuAgRAAAQGIADlD8qf1FsD2EEABEAABEAABEAABEAABMYXASh/AwyAcRoEQAAEQAAE3m0CUP7e7fLH3YMACLwzBKD8QfkbX+8y4C0IgAAIgAAIgAAIgAAIgIAUASh/78xQHjcKAiAAAiAAAkMhAOVvKNRwDQiAAAiMOwJQ/qD8Sb01gB0EQAAEQAAEQAAEQAAEQGB8EYDyN+6G5HAYBEAABEAABEaTAJS/0aSNvEAABEDgrRGA8gflb3y9y4C3IAACIAACIAACIAACIAACUgSg/L21oTUyBgEQAAEQAIHxQADK33goJfgIAiAAAsMmAOVvjCh/rZlpyUHewgF8we4v1SG+8e6Tm9SJwrOjYDHrdQqZi6G5aRTycmIWvVWVaWGhyQGeLx7ed2KyUkmVnT1ZsPML4dnMiLC6u7eFdmqpv3c7KUCu9Jr5/MpFbpxGlUId4qte4KOrqebaeeHmVHVyoFfqspDuZyXcU1J2bpyJFB6hKmo1mxUyF1111URihXsBARAAARAAARCY8ASg/A17iIwEQAAEQAAEQGAiE4DyN5FLF/cGAiAAAowAlL9hKn/6ulqlx7S+psZhvkSQUv5osprQgOEof/UP7qYuDR6ahw7KKm3ZmaLKpTDT4TgjTE3KUnos9vG2Teyss4qJEPJKEKqrYYkTQoai/FksSrmsozCfmw4Np69YXP3rL8zenpejkLlw/+of3GVni77ZVfzt1+yQBaTsLAIL9FZVZkaEKb1mqhf4dBYVMLsTA5b+fs2SIKXXTPtpDq1uWE2mmhtXzX16+4kPtg44R/mzWDShAQ0Jj3i+DdYZ3uU4BAEQAAEQAAEQAAEpAlD+2FAXARAAARAAi4nQDgAAIABJREFUARAAASEBKH9CJrCAAAiAwAQkAOVvmMofIaRw97aSIwelxt4O2kdU+bOazeoQ36ZklYPOcKM5XfkbjjNcx+yHC/dsLz1+mBvHKcXkROXP2NaqkLmY9TqukzSsXuDTkpbC7FT5M/f2WoxG+kcsFnb2+ZWLj7e+1jgHtLMILJC/Y3PpsVhCSH9np7G9jdmdGHh26ljWxysGVP5Gum4Mqg44R/kjpO7OzbTwRUKYg3JGeDksIAACIAACIAACICBKAMrfBBy045ZAAARAAARAwHkEoPw5jyVSAgEQAIExTADK3/CVv97KCqVc1t/ZwR17U9mgOu5K1rpwdfC8p4cPsLMlRw6qQ3xVnrLUZSH1914tBUmVv9KTR5SeMs2iwEaVgsUnhAjn/HUWFWRFrlR5z0rylz/eusnQ2sKNLwzX3LiasXqZ0G7u7X16+IA6xFfpNUO7fnVfYwONUxV3Wb3AJ9F3dnXclderfVos5ed+UAfPS/Sdnbd1I81UV1utCQ1IDvSKn+WqCQ3QhAbw1q4UZirqzOOtm8rOnmSR87ZsKP/xFD1sz9VmRixXes1M/SikNSOVxdHVVOdt2ZA030M1z73gqzcW2yzYtbX05BEWkxAiWkwlR2O1UWuSA70eb9tU/O3Xib6za2/9SggxdXXlbdmQ6DdX5T0ra104mwmXseYjTWiAQuaiDvbVhAYwya3s7MnH2zYV7tmu9JiuWbKALb+ZGRFWevw7zZIFKu9Z+Ts2m3q6bS69nAeWstBPIXNJCfXXhAZU//ofXFeTAuQt6RpmocqfxWhkFm6g6pdLeZs/5VpoWMoujFn0za5np44J7c6ydJeWZKxa2pDwaEDljxAiWjda0lKSAzyLv/06a114WlhosyaZ+aaNWpMS6v+6irITYgHROkAj5sZEPzt1rOCrL1IW+iUFyNtzs1814etxmtAApaeM24QbVfGpS4OVXjMyI5azuiGWoc1mNfUnB3m3pL0uUBrTjjNSScEOAiAAAiAAAiAAAgMSgPI3hgffcA0EQAAEQAAE3j4BKH9vvwzgAQiAAAiMAgEof8NX/ggheVs2lJ05wR2HU9ngyaF9dCqV0msmUwiqfrmkr6slhHQWFybMndqRn0cIac1MU8hcKi6csZpMLWmaePcp+hf1LEGh8teel9OckmTu01sMhoJd27I/XcciiwYsRmOSv7xNm8k7m7dlQ87G9cbWVqvZ3J6TpXu5iGVrVrrSU9ZdWmIxGPJ3bGGySu2tX1MW+unr62yZ7v6Sm6njq33alC8xZ5qSlCmh/tQ9U3dXwuwpulrbLne9VZUJc6c2JiYQi6U9L0fpKaNkzHp9cpD3s1PHzH16c5++/vc77NZMvT2aRYG1t68zCw0Ii6nkaGzBV1+Y9TqlXFZ393Z7ThZdFtXY2lpz42p/ZyexWGpuXFV6zWCLSb6aCiZY7TNh7tS2rAyL0Vi0b2fOZ5E0x8yIMHXwPH19nVmv10avLdq/m7lkaG4SnfPXU1GmmPmBrvo5i2lf+bNtCrjAx+bqmx8p+5uxbEcvHt5XymW9zyuEp4ZvsZpM6SsWdxYVNCYmOKL8idaNlrQUhcylQfE7IaSn/JnSYzpX6nZwWiq9F2EdoPbcmOhE39m0MZr1ekNrCy3ox1s3mXp7esqfJcydSptwb2VFwuwpbdmZVrO55uY11Tx3c2+vfVBVcVeyIlcK40g5I4wJCwiAAAiAAAiAAAg4SADK3ygMopEFCIAACIAACIxfAlD+xm/ZwXMQAAEQGAQBKH9OUf46iwuVXjPNutcrN1LZoLO4kA7Rsz5ewab3cQft2qg1Vdd+pspfvPtkNq8rY/UyaqeRhcofNxGbHjbQDmqEkOdXLmqjIrgXGlqaFTIXKkNy7U8O7SvY/SW19JQ/Y8qfNmpN5aVz1K6rrlLIXEzdXfRwUMqfqDOW/n6V96zOYts+c7W/3ciMWE5Ttu3Yx1nNMjcmmpJpiH+gDvYlViuNxv4tO308fpZr5towq8nEjDQgLKaSo7Hl52wTDTWhAR35eX2NL1Tes3hXEYslfpZrd1kptUspf9rotTRCa2aaeoEPDWdGhNH0CSEtaRpuMYkqf9rIVQqZS+mJN9Yppcpfou9s9tdbyVHprNacjesVMz+gMvNr56Xsr2PYQu15OalLgmpvX9csDqRTEuvu3GT19s24tqOUUH/mBg3kxkQLozFLxcWzTw7uJYQ4qPyJ1o2WtBSlxzRW1pkRy2t/u8GyGJTyJ6wDNJ3cmOiifTtZmmxZ1/b8XGrMjAijTbjiwhmu5p0UIB9wHV1znz7Rd3b74xxu+lT75/UbvAg4BAEQAAEQAAEQAIHBEoDyN4jBMKKCAAiAAAiAwLtHAMrfu1fmuGMQAIF3kgCUP6cof4QQbVQEd5XLV/pQdRUdq2uj1tTcuErDdXduZqxelrLQz7bGpse05z9fospfot9cNrDP27KBuwCjUPnra3xRuHubZlGgOsQ3OcAzYe5Udq1UwKzTMWmNxukozFfMeJ8JKuzCvK0bn/3waqlMU3cXU/40S4Lq7/9Go5l7exUyFzZRbLDKn9AZQkjxgT10x0TtJ6urr8fRjB5v26Sa565ZEkT/koO8y8/9QAipvHxeG7WG+cwNGNvbkoO8G+Ifco00zCsmm/J3/rRN+VsS1FlcYGhuUnnKbLMS+/tLT3yfujRYHeKrDvFVzHifiWFSyl/BzlfLjbbn5ST6zqbZZUaE1dy6RsPdpSUKmYulv58eiip/hJCO/Lx498ls2VUqzlGB1tDcRP+4omZrVnqi7xxDcxNNlv0rZWcRaEAbtaYh/gEh5Nmpo7apihZL3pYNQo2KXWVobWFu0ABvnVsWkxCiq65SL/ChgqLjyp+wbtDVPlnKuZ9HVVw4ww4HpfwJmypNJzcmmqna1CLVhJ8c2lf49XaWe/qKxTU3XxUxMwoDFRfP5mxcL7TzKqQwAiwgAAIgAAIgAAIgMCgCUP7eyWE9bhoEQAAEQAAEHCUA5c9RUogHAiAAAuOaAJQ/Zyl/bdmZSf5yNmlPSjZoz8tR+bj3lD+jA3jt+tVUL2zNTOPN+ePu/Za6NLgpSckd82uj1jw9fMBiMNiUoVxtwhw37lmpcNnZk3lffMbOSs75i/2m+MAeGk1XU82UPztz/tpztcmBXixlRwI8Z6jEleQv1ze8SJg9pb+jnSZSeiyWThrjpSk1549Gy9+xuez0cd4lhBBeMQmVP6XcpvxVXDiTuTaM+mA19cfPcqWTEW0JWiwKmQtdiZSlX3b2pJTyx53zp/JxZ5dIKX+EkETfOW1ZGSym/dU+q+Ku5Gz6hEVmASk7i0ADacsXNqck2cIWi61SfbdfsyjQ1NvDi8YO1cG+Sq+Z3D/R3Gn8BsXvCpkL76+r5AlLTSrAqxstaSkJs6ewxpW2/EPuUq6DVf54dYD6kBsTzVXu2Zw/nUC8H8KcP9vOkT3ddAVd3i2LOsOLg0MQAAEQAAEQAAEQcJwAlL9xPTyH8yAAAiAAAiAw0gSg/I00YaQPAiAAAmOCAJQ/Zyl/hJDMiOVs9o+U8tekVqUs9LOabBO/bPv8zZ7ClL9X+/yZzS3pmoQ5btxZX/nbY54ePsAd8KeFhdbduWnTJ0ym/B2bHVT++js7bTu6cdaKzI2Jfr3PX14OXfmzPScrOcCTbh1XevwwU/5qbl7j7vPHXTtUV1Md7z7F0NLMddJ+WOgMIUQd7Jv92ce5MVHs2p6KcqXXzJZ0jdVsthgMrRmpVHUz63TJgV5lp4/TzQ5fPLrPLiGEFOz+svT4G2tmsrPcYpJS/kqOHCrcvY1eUnX1Z4XM5bXyR0hSgLxRpWAJEkLsKH/qYF+6z1/2p+u4C3LaUf6Sg7xb0lJY+lT5M/f2WoxG+mc1m9nZ51cu5m3dyA5ZQMrOItBA+bkfsj5eQaU+XXVV/CxXXk3jxe9rbNA3vOD+GdtaeXFEDx2f8/dqa0xORaX7/JWfP201mZrUiQlz3LhzHAer/PGaKvXWceWvp6L8jX3+fNztCKVcFKUnj+Tv2My10DC3QgrPwgICIAACIAACIAACgyIA5W9MDLPhBAiAAAiAAAiMVQJQ/sZqycAvEAABEHAqASh/TlT+mtSJ6hBfqspIKX/EYnlycG/q0uDszz5+EvsNW+uvNTMtOcj72amjSk+ZZlFgk1rFHeHrqqvSVy5WekzPWhdO7e35uWnhi7IiV+Z8Fvn850sOKn+EkJKjsWwPP9tUpN6ep7H71cHzlJ6yrMiVfY0vaPpVV39O/SgkK3Jl6YnvmfJnNZvLzpxQL/BRzXPP27KBq77QlJMC5MlB3rxVE7k3wgvznLFJaKePK2QuvIU623OystaFq7xnqea552z6RFdXQ9PRVVflxkQn+s1V+bjn79jCTbzw6+2lx7/jWliYW0xSyp+htSX703XpK5fkfBZZdfVnpVzGVf4aFL+rg32TA72YQmlH+Ss9cTh1abDKe1bBV1+Ye3uZG3aUP3XwvGZNMotJlT/uzDm6QimNUPnTj4+//JxFZgEpO4tAA1azufzcD2nLF2ojV2VFriw/94PKe5au+jkv2vAPB6X88SpqS1qKOti39Ph3ttaxOLBJnUj9aUxMsC3HGuyrkLmoF/ioQ3zZarT2HebWARrTceWPENKQ8EizZIHSU5axellHfp79vNhZY1ur0mO6rqaaWWhA6AwvAg5BAARAAARAAARAwHECUP6cOlxGYiAAAiAAAiAw0QhA+ZtoJYr7AQEQAAFRAlD+nKj8EUJSPwp58fCNyWeOj9JHJ6ahuUnpMV1fXzc62dnPZeSceXbqWPan67hz47iejPFiylwbVv7jKa7DkmGr9fGXn9PNEd+II2V/I9KYPuDWDZvyF+LrXHffSh14Gru/6Jtdwht5K84I3YAFBEAABEAABEBgAhCA8ic67IURBEAABEAABECAEoDyh5oAAiAAAu8EASh/zlX+2vNzGxS/j/FXBi8e3Xd8otJI38sIOdPX2JC9YV1ykLeoEDvGi6ktOzN95WL1Ah/h/DBucTSnqtULfLRRa9gkSHpWys69dlyEWd0YCeXvrdSBvqbGysvnidXK4/9WnOH5gEMQAAEQAAEQAIGJQQDK3zsxjMdNggAIgAAIgMBQCUD5Gyo5XAcCIAAC44oAlD/nKn8T430B7gIExhSBkVD+xtQNwhkQAAEQAAEQAAEQcBYBKH/jajgOZ0EABEAABEBgtAlA+Rtt4sgPBEAABN4KASh/UP6c9ZYB6YAACIAACIAACIAACIAACLxdAlD+3sqwGpmCAAiAAAiAwHghAOVvvJQU/AQBEACBYRGA8gfl7+2+m0DuIAACIAACIAACIAACIAACziIA5W9Yw2NcDAIgAAIgAAITnQCUv4lewrg/EAABEHhJAMoflD9nvWVAOiAAAiAAAiAAAiAAAiAAAm+XAJQ/DPRBAARAAARAAATsEIDyZwcOToEACIDAxCEA5Q/K39t9N4HcQQAEQAAEQAAEQAAEQAAEnEUAyt/EGavjTkAABEAABEBgBAhA+RsBqEgSBEAABMYeASh/Y0T5a81MSw7yFg74C3Z/qQ7xjXef3KROFJ4dUYtZr1PIXAzNTSOayygn3ltVmRYWmhzg+eLh/VHIOityZe3t67yMLEajQuaiq6vh2dlh/b3bSQFypdfM51cuMiMh5NkPR5IC5OkrFnONwnBzqjo50Ct1WUj3sxLu2bIzJ5L85dqoCLNez7VPgPCTQ/tU89yVXjM78vMmwO3YuQWpumHnEsdPjXLrsO9Y6fHDxQd2249DCKm5cVUd4qvylJUcjR0wstMjNKoU6hBf9QIfXU210xPnJWg1m239RnUVzz5gfyLaOiwGQ86mT5L85U9j9/MS5B1K9Rva6LVJ/vKS77/lxZey02gOdmK8NEfi0PEHnCY0QL3ARyFzMfX2DNmT/s4OdfA8dfC8Fw/uDTmR8XXhaLYOQshbedpKtQ4p+/gqQXg7rglA+Rt7Y254BAIgAAIgAAJjiACUvzFUGHAFBEAABEaOAJS/YSp/+rpapce0vqbGYb4gkFL+aLKa0IDhKH/1D+6mLg2W8jArcmXd3dvCs1aTqebGVXPfKKlEhXu/enJon9AN51pKj8U+3raJpWmfDIvmSODVe/k39byhvIu0WJRyWUdhPi9Tc2+vQubSU/6M2cvPn1bIXLh/+oYX7GzRN7uKv/2aHdKA1WRKXRLUEP+Q2Z1IgKXJAs5qHfbrRmdxQaLvbLNOx/J1VqDmxtWMVUvj3adkf7pugDQtFk1oQEPCowGiDXR6gOKQqBsDpero+ZFrHVIetGVniv7igRDSUfC4PTdb6kKevfjAbp7yZ7/O8C4f8mH6isXVv/7CLndipkIyQ1P+pFpHc0pSUoDc0t/PnM+NiaadidJTpo1aw/3dgLDfoFf1NTbYfh3S2sISsW/nd2JOajW83HmHTnnAGZqbBqX8lZ09WbD7S54nhJAXD+9rFgcK7aKW8nM/JM33UHnPKti1TTTCkI1OrKh2fOC1jgE6NzsJCU6N/tOWEPL8ysUkf7nSY3r+ji3m3l7mlFTrkLKzC1lAqjik7OxCBEDADgEofyM3dkbKIAACIAACIDABCED5mwCFiFsAARAAgYEJQPkbpvJHCCncva3kyEE7w29HTo2o8mc1m9Uhvk3JKlFPpF6MikYeOaOuukrpMc3Y2jpyWdgKa8/20uOHWRb2ybBojgSc9S7S2NaqkLmY9XwdS19Xy7OXnz+dGbHcYjSyP66fz69cfLz1tcbJTuVsXM/VKpxIgBDS+7yiOSWJ5eWs1mG/bjQkPMpYtZSbqbPCTUnKlrSU4gO7B1b+CKm7czMtfNEws7ZfHFJ1Y5iZsstHrnWwLHgBob7Fi+DgoVD5s19nHEx2wGjqBT4taSksmhMzFZIZmvIn1Trq793mtZrcmOgnB/dazWZzb2/pie95iiyv32C3nDDHjftzBPt2YSfmlFbDMhUNOOUB5yzlr7O4QOU9S9RPnrH3eYXKU2b7UZHV2ltVyTs7zEMnVlQ7nvBah/3OzU46wlOj/7RtSlbZfpGTn9ff0Z65Nqzw6+1cr6Rah5Sdey0hRKo4pOy8y3EIAqIEoPwNPAZGDBAAARAAARB4hwlA+XuHCx+3DgIg8C4RgPI3fOWvt7JCKZf1d3Zwx970zVR13JWsdeHq4HlPDx9gZ0uOHKTL06UuC6m/92qyHVX+Sk8eUXrKNIsCG1UKFp8QIpzz11lUkBW5UuU9K8lf/njrJuGsC+7ldE28jNXLeMaS77/VhAYkzJ2a6DdXExqgCQ0w9/XRONqoNSmh/tzVPk29PQqZS/6OLUn+8qq4KykL/dJXLqarn5n1OttNBc9L9JtbtG8nW0zS1NP9eNumRN85Kh/3zIgwQ0szzwHeYf72mNIT3/OMj7duKjt7khnztmwo//EUPay5eU2zJEjpNVMbFaGrfb3aXltWRmZEmNJrZnKgV1XcZXYtIaRg19bSk0e4Ftu8LgGZtPBFuTHRiX5zy86c0K5fneQv73paTAiRwp6x5iNNaIBC5qIO9tWEBjDJLSty5bNTx7I+XqH0mJ69YZ2pp5sQQlfnq/zpx6QAeZK/vOzMCWK12lx6OQMmZaGfQuaSEuqvCQ2o/vU/mKu6mmqb8vdHARFCXip/YSwCL1D1y6W8zZ/yjISQ3M+jquOucO2iBLgRHA/XP7ibt3UjN75o6+BGcDAsWjc6CvM1oQFJ/vKEOW60AncWF9IEq+Iu52xcX37uBxqBrptaf+926kchSk9ZykK/0uPfcSc82akzpccP85Q/c2/v08MH1CG+Sq8Z2vWr+xobCCFWU39ykHdLmsbBO5KKJl4c0nWjq+RJwhy3xsSE1GUh6gU+uTHRdiqq7S1zTXXelg22uUTz3Au++oLrhoOtgy6TWHosVhu5KvWjkIqLZ2kipq6uvC0bEv3mqrxnZa0L7ywqYIkLi0NXW60JDUgO9Iqf5UrLjq1t25Ss0oQGqLxn8Vb7FO05aRZC5Y8QIqwzVrM50W9uW3YmvcpqMiX6zqYzC6U6MUKInbqRFCBvSX+jxIWZEkIG1Z9IkXn1TLkepwkNUHrK2DNFqj+x0zoIIbW/3chY8xErIFvPEBPNZl13PytRyFy4v8MQ9hv0WqXHtO7Sp9x07NiFnZhUq6GNLjcmKmPNR9rIVWwxVTtNWCmX1d+7bXvghviqQ3zNOt2gHnD2W43jyl+D4ndb7fVxV3nKaMXmTl3telKk8pQJcQkt+oYXCXOnjsRUZpqXsKLaaR22rxCDf9oKW4do5zao1kEIeStP28dbNzG1rzklKWGOm8VgYKUm1Tqk7OxCFvj/2bsTv6jq/Y/j/8pvqnu73gwzVFRwI1coTbOF3NKrueSVdqxIyyW3MusapXb1pqWVdgMHAVkEBMQFQRFBAdkc2YZFBo6RUvN7jF/v8Tgb84VhGGZePHh0z5z5ns/5nuc5M9zveXvOsd0djnaTuggTCDgXIPnzp9E824oAAggggIC0AMmfNBkLIIAAAgNRgOSv98mfoig5q5Za8hvNjzhLK06k3qyt1Y8drp4HL/7266bSq5bzjOfOHB39hHgyWU16amzgoEtf7ehoa6tOTY4LCmgqL1Pr2SZ/hpysquMJpuam9paW01FvWCUT6oLqRHtra8KkkOuZ9055q/PF03Hs3u3T6jFIIvkzllwu/Nf2489M7Gi7mblojkgoz6x+I3PJ/Ju1N0xNxlNvrMj7+ANR/+KObSdfXWA5QdbeXnvudFtdnXa9ttP1Bfn6MYEiHlPfrUzQH58+Sbxsq687OjJAhHylP36fOHVcw6WLHSZT8bdfpzwXrrS3K4pSd/7c0dFPVCboO0ymm7U3tBlqW2ND8owpVg/esyuT+uKMqz98Z8g+KR7IV/jlp+JpWE7YHV2FkPzsFOPVkpu1tanPP3N591dq8pe14h+mJqOx9IrloYO/3n/ooDjFbHvN35Xv/5MwKURl6Tb5szxjadr4m7W12kUURTm/fk1O5LKOtvt3+bMrYLWUiy9tkz+7nw4Xq2mb2T02RINrsUesrl5SFKV47y598NBikXF2dIhjpvyXn+vyzna0tbXUVKc8F1709ZeigpNjRlEU2+QvZ9XSrOWLWmtqOkwmQ1aG+sjG4r27MxZGaLvdg2knu8PusVGXnxc7/LEz77/V3toqLh9RFMXRgWpqakqcOu7C9i2m5iZTc1PZkR/VHrr+6RDfDCKWMzU2Hp8+SVxP3FpTc+XAPssh195+5cA+/dhh6r2C7e4OS6jm+G6fts/5s/vNKfpvN/mze8zkf/LR2Q+jxFLVqceTpo0XubujLzEnx0bDpYuxwx8zllxWDRVFsbvSHnyf2MqIb5hTr69oa2xoKLxwdPQT4m+KSP4cfZ/Y/XR0mEyno14//e4Dua82+bv01Y7EqeM6TCZ102y/N8RbKbPCLu/5Wm2mTtidb/sldvejaudTU7B149FRQ8Qn68qBfakvTBeVHX2EFUXRhwSeeHmWeDBt07VyNdd3dM2f1R84J58aRVFcT/5EPx3d7bO1piZ2+GO15+6H4qqY1UR7a2vKc+FnPnjHar67Xto9UB19Onrw19bup8Pul1sPPh2e/2ubMnNq8bdfG05llezdLS5dbSy6pO4LR58OR/PVBdUJu7vD0feJuhQTCDgRIPkbiKNy+owAAggggIDHBEj+PEbNihBAAIH+FCD5c0vyV3vujH7scO0/zxdnptQrkDJeeUm9vE87UM9cPLf4P3sURalJT40Lelycu7f8q/Y5z4n5orFt8qctYsjJ0o8drp1jd/ry7pjMxfNs33LxxKhI/pT29muxR0TQeDb63ZLvvrV6dFNdfp7amcIvP02LmGm5F5y4ps123TZzspYvUi8hEm+237wZP26EOFV69dCB9HnPi/kPPEOoo0M/JrD+YoGiKOfWvnfmvQfuxCXaX/x8a9yIwenzX+hoa7Nara1M6oszDFkZLVWVcUGPWx7O9MvP6mV86rJW7I7ORV6KuRcvXdi+WXRMnKk3ZGWIUgXbPtFeJ2eb7tysvRE/Pigu6HGr+7UW7vw8LujxY6Ejxa+aj97rYUdH1vJFscMfU6/jEfNba2qSwkOPjhpS/t/7caOtgLqZrkw0Fl0SfYgfE3h0ZICYFjGnSLitPh2u1LRtY3tsiDZ2s43ivbuOPzPRtog6p3Dn5yq7o2NGNLZK/lqqq2IDB4nwXq0mJkzNTZZryE5lWc2Xfelod9geG5aoOz8vNnBQc8X9RzxarU57oF6L+yUpLNT28yj16RCRifpPGS58tul01OtWK1Xa2+NGDBYfSRHE2t0dtvmWWsc2+VPfUhRF/eYUM+0mf4qi2B4z4rtaxEKno16/8JnlCmAnX2KOjo3MhS/HBg4q2Hb/1sFq92xX2oPvE1sZ8Q1jyM0WK0qf94L4m+L8+8T201GVkqQPHpowMVhNrEXB7JVLLPMnhehDAo89NVpdkXjX7veGJS3LytAHD9WPHa5elifaW8139CVmwbf3qSnYujFr2UJRytTcbPkXGFfuX9Ut5ms/wiL5K//lZ/GW9r8u/oHTLiJSQPUPmRuTP0VRinbtjA0c5OTJu6InWcsWXor5In3+CyX79yqK0nq9xupfF2k7fPXQAfUPgTrR7ReR7YFq99OhKIrsX1snnw7bL7cefDo8/9c2ccrYqwf3X/pqR1rEzJu1N2IDB2njW0efDkfztftOnbbdHfeOBJv/U6QuwgQCTgRI/vpzdM26EUAAAQQQ8HoBkj+v30V0EAEEEHCHAMmfW5K/u2ei56l3q7Pc+s9kspysLCkWw/LMxXOvHNgnpkt//P7EnOeOP/2U5W6BwUPFBRM16anHnhqtjuFzVi29sH2L+tI2+WuuKD+z+o3kGVOSwkMTJ485OvoJtbGjCZPRqEZo2jYunhi9l/wpyrWjv2YtX3Q3Y1tdsnc9QLIRAAAgAElEQVS35Z/2Bw5KmTk1Wfw+O+VY6EhxyZqpqang000ps8L0YwLPvPeW7XVs2m6IacOpLMvizU3at86tfU88STHzH3PEaVBFUeLHByVNG39vpTOnJkwMrslIUxTl5LJXCnd+rl1cnW41XE+cOu5a3H/VOWLCVsZyLjInq/V6zdFRQxRFuRZ7RNw50wm7o3OR6iWGhTs/z31rpXrNn/ropuK9u9Pn379pp910R5wvTn52irbnhTs/T4t4tqWq8t5vTbX23ZqMtGOho8QVMNr5F7ZvyVw8T3unMsvJdwfHhnZBJ9OWq+judqN4356s5YvEtDYIz1z8wKfDSSknb9k9NsTesXvNn+2FsIacrJNLFxx/ZqLldrvjg7JW/EOszskxY3vN340zubHD/m4bnolSl2K+EJ8OJxvS7VuOdofdY6MuP0/k09qyjg7Uol07MxfP1bZUp13/dIjkT01iir/9WtRsv3mzYNsnKbPCxO0WY4f9Xf2nD8V7d9nuDtlr/ux+c4r+O0r+7B4zyc9OqUyMNzU36YOfbLhUqCiKky8xJ8fGjdycuKDHxb1eVUZLaGTzJdaD7xNHyZ/t3xSR/Dn6PrFN/sSdabNXLjn30fvabmevXHLmg7dbr9c0lZVeObAvfkKQNk62+72hKEr6/Bcufr5VW0dM251ftGun1ZeYaGz7qSnYuvHM6jfUsvrgoYYcS6Du6CMskj9xAb26lJhw8Q+coiiOPjVuTP5MjY1HRz8h/lRZ9VP70pCTJaCaKysSJocYsk/WF+Tb/Yc7YilTk/H+H4L//UVQr3rUVtZO2x6olluL23w6evbX1tGnw/bLrQefDs//tRXX/Ak922v+HH06HM3X7gV12u7usPt9oi7CBAJOBEj+3DFKpgYCCCCAAAI+K0Dy57O7lg1DAAEEtAIkf+5K/q6fTE+YFKJetOco+TPkZMWPD7JcBnf3J3PRHJEX2l7zp33GW8qssMoEvXaEn7l47vmNa0V+Y8jOFAGVtoHd6YtffJoTuczqrcxFc0p/+sFqpiUNajLaPufPErRokr/ivbtEIqh9IpRtqebKiuSZ0+7detH27QfnZC58uXif5TpI9ceQk5UwKcTy3KORATdvGMT8tJeetc3wnFzzJ5bKffufds9TW8nYnosUj09zxt7ebsl6NY8bFHdSdZT8aa/5O/XGCnVj7aY7iqI0Xr4UGzhIe5fObp7zt3e3mmypxcW9N+3enc9KQLuI69N27/YpAh7tp8P1glYtbY8NJ8mfVQLX3tKiDx56Le4XEdoVfvmZ2sDRdV1i7a5f86coSltDveXy04J8q57LvrS7O+weG+I5f1b1HR2ojq75E4u7+OkQ3wyG7EyxVP6mj8V9Iy99tSN9/gviE9rRdjNuxGD1shjxnD+rTlpOamdnJk4ZaztfBK7a5/w5+uYUy55fvyb/k4/s1rE9Zi59tSP3rZXXYo+o95B08iXm/Ng4FjrqesYJ2/VarbQH3ye2Mo7+pthe86f9PrGb/InHtmUseFHbc+3dPhVFSQoPvfLDf9QGOauW2v3e0I8JVPNdtbElh7M33/ZLTCxi+6kp2Loxc9Gce+/W14l/RuPkIyySP/V40/bExT9w4kJSR39Vb94wxAYO6vaG1ep6C7/87HTU/eRSnV9fkO/KP9OpTNCnvfSsWOp6xomEicH5n3ykPuBWraZOXP3hO/3Y4Va/IitV29idsDpQFUWx/XSIa/568NfW0afD6sutB58OxeN/bR94zl9yotVz/hx9OhzNt7svLEegzf/5ES0dzXdUh/kIKIpC8qcd7TKNAAIIIIAAAlYCJH9WILxEAAEEfFOA5M9dyZ/l6od5z1/5/t6pUkdnaSuT4o8//ZTIbyzP+RsZoCZ/957zZzJVpyUfHTVEeylJ7lsrz29cqz2XkfrC9NIfv7979UZb7tv/dDH5szxxMCRQ+3waRVFOR70uHmKnre968mep8G5k7lsrWw3XFUVpKi9TH61Xk54qkrCbtbUps8Ls3u/UaqWKolSnJVseMaV5EJ3lNHRY6Mllr2SvXKy2v3pwf8qsMLEtbfV1ZUd+FE+lqss7e3TUkMrE+A6Tqa2uzioxPb36zYKtdm7QZyXj6Fykc/aEySHqtot+ZiyMcJT8aZ/Lde3or+p22U13LM9vK70SGzhIe93k3eTv+fbWVvVXeyHa5d0x6t0s1eLi/ofaG8mqb1kJiPntLS1566Irk46pzZxPOEr+rD4dapGib/5V/K2dh4SpDawm7B4bdrMN26ipra4udtjfxZVqN2tvJM+YoiZ/jo6ZDpOpvbW1YMt6y1WSra3qfWKzVy65/5y/nCyrO38WfLop9+1/WvW8Ij4ub1209sFpVg2sXtrdHXaPDbvJn6MD1WQ0Jk4Ze/HzreIRodoHTFo+yK59OkTyd/cAbjJeKTn21OiK+DhFUfI3rVOv0yret0d7Qzzb3SG213ilJC4ooKW6ymrzbZM/R9+cYsErB/alRcxU/+GFtprtMdNUelUfPNRyMv3f36gtHX2JOTo2xIKJU8dVpx5Xi6gTVivtwfeJrYyjvyki+XP0fWL306EoSulPB62ulLUkfx9/0GEymZqMVSlJcUGPa58Lm7V8kd3vjaOjhqj3dFU3X1EUu/Ntv8TURaw+NQVbN8YOf+x6xomOtraCrRtTn3/aEqs7/gg7Sf5c/AOnKIqjT43opHqcq312MnH10IG0l561+it299bHp7U3EXVU4WbtjWOho67p7/1dOB31Ruzwx8RfWLuLmIzGpmvlVr92Pw5Wi1sdqJa/4PY+HT37a+vo02H15daDT4eiKB7+a1uZGB9/N8xuq6vLeOWlM+8/cEdxR58OR/Ot9oL60nZ3iLcczVcXZAIBWwGSP98ct7NVCCCAAAIIuEmA5M9NkJRBAAEEvFuA5M+NyV9l0rGk8FBxct/RWVqlvT3v4w9SZoWdXPZK3voP1bsg1qSnJk4dd2H7Zv2YwOQZUyqT4rXDeGNJcVrEs/rgJ9WrNAy52akvzshYGJG1bOHlPV+7mPxZzs5vXn969Zva4vUX8lNfmJ4wOSRx6jhTc7OiKBXHjlru1xcWGhs4KGna+KTw0LLDh+ze7bN47667GWFT/ub1ljsojgnU3hTryoF9x6dP0o8JTJw8Jn/TOtdjj7SXni396aC2kxc/3xobOMjqsoMr3/8nZVZY/JjAxCljLY/Qa28Xi9ScSDkxd7Z+7PDEyWO0J/cVRTnz/lsFWzdoK6vTWhlH5yKds1+LPZIUFpo4ZayaUDpJ/i7v/iphckjCpBCrKznspjuWE7JlpZbkz2hUO1y48/PYwEHaX+1FHkXf/OvUm6+pjdWJk0sXqHdMVWeKCa2AmGM51R44yNHdU60Wd/5S++lQW6Y+/7Sjm0+qbawmbI8Nu9mG3ajp6g/fJc+clrl43qk3VpzfuFZN/iwP2rR3zFzYvlnLqyapbY0N59evSQqboB8TmLEwQntTRPFELn3wk+rNMEX/8z/5KC4oQM0OrTbK7kvb3WH32LCb/Dk5UI0lxdkrlxx7anT8+KDct1dpV+3ip0Mkf0W7diZMDNYewC011SdfXZAWMTNr2cLifXv0IYHqNVh2d8c9mc3rxZdP0df3noiZsTDCcifkscPixwQmhYemPv+MpaWDb05RxNTclBO5LH5MoD4k0NTYqN0occWS1fdJxoIXY4c/pk0cTU32v8QcHRtiFUlhE6qSE61WJ15qD9SefZ/kPyjj6G+KSP4cfZ/Y/XQoilJ2+FBaxL2rykSHs1cuEUe7PnhoynPh6u2pxbuOvjfiggIa7t4x1QrB7nzbLzF1qdbrNdpPTcHWjadeX3Fy2Sv6kMCMBS8aSy6Llk4+wtrjTS2rKIqLf+AsV6A6/atq+QabNl4fEiieDaldhe20qbExa9nChInBiVPHqZd3K4py4/Sp+AlBtu1t59QXnM9cPC8tYmbmwpfPfPD2yaULzq5Zbdus93O0B6qoZvvpEBeJyv61dfLp0H659ezT4eG/toqiXN4dkzAxWB/8ZO7b/7T6knH06XA038les90dorGj+U5K8ZafC5D8eff4m94hgAACCCDQzwIkf/28A1g9Aggg4BkBkj83Jn+KoqTMDi//72FvPt3QUlWpD36yqazUmztZER+bPGOKmuS5sasXtm85+eoCuxmkl8uYmpvigh43ZJ90SaOj49Sbr4mHI2rbm5qaksImVCY+kCurDWwFak6kWC4/raxQ2/RmwurTYWqybJG4XMz1sn13bLjeh25bnl+/5uyHUdpm6fOeP79hjXZOt9O2u6PbRXrZwMVPh0j+mq6V93J1Hlu8746Z9PkvWCX36kb13UrVVfRmoiYjLX58UFt9nStFHH1v1F8siB3295u1tVZFHM13/iWm/dRYnvP3wTtWZX3gZfF/9txLsr1mY/ruQHXy6fD8l5uUt/MD1aqUo0+Ho/lWi1u9dLQ7HM23WpyXCKgCJH+eGUezFgQQQAABBAaoAMnfAN1xdBsBBBCQEyD5c2/yZ8jNvhZ7RB14e+dE+a+Hb+TmeGff7vWqo6No186Wqkq3d7K54trJpQsSp46zG9B6uUzxvj3Jz05JfXGGc5aqlKSkaeMzF881ll7Rtry4Y1tS2ITTUW84uQuclUDB1g12b46qLev6tNWnoyo58cSc51xf/F7LPjs2pHvieIHmyoqiXTvVm6+2NTboxw5rvV7jeAn771jtDvuN3DfXxU/HgEv+lD47Zq6fTE+LeDZp2nirSzwt+6TPVuqWHd7R1nY2+t2ksFC7t3rWrsLR90bmkvnJ0ydbjvMHfxzNF62cfIlpPzW+l/zdrL2RNG186gvT7d4e9kFCz77qswPV2adDUTz85SZr6uRA1ZZy9OlwNF+7rP1pR7vD0Xz7VZiLAM/5kxsO0xoBBBBAAAF/EyD587c9zvYigICfCpD8uTf542QDAggg4NsCAy/58+394Ytb53vJny/uJbYJAQS8V4Br/vx0YM9mI4AAAggg4JoAyZ9rTrRCAAEEBrgAyR/Jn/eet6BnCCCAAAIIIIAAAgggICNA8jfAB+h0HwEEEEAAgb4VIPnrW1+qI4AAAl4iQPJH8idzJoG2CCCAAAIIIIAAAggg4L0CJH9eMtCmGwgggAACCHinAMmfd+4XeoUAAgi4WYDkj+TPe89b0DMEEEAAAQQQQAABBBCQESD5c/OAmXIIIIAAAgj4lgDJn2/tT7YGAQQQcCBA8kfyJ3MmgbYIIIAAAggggAACCCDgvQIkfw4GvsxGAAEEEEAAAYsAyR/HAQIIIOAXAiR/XpL81aSnJk4dZ3sK4fTqN5PCQ+OCHq9MOmb7rgfmmJqMsYGDWqoqPbAuN66isbgo9YXpiZPHlP/3sBvLOip18YtPT78baftu+rwXSn86aDtfzCn7+WDC5BD92OGXd8do21TExyaFhyZNG2+8UqKdbzVdlZKUOGVsynPh9RfytW85mq9twzQCCCCAAAIIIICATwqQ/PnFMJ6NRAABBBBAoKcCJH89lWM5BBBAYEAJkPz1MvlrKr2qDx7aXFnRyxMHjpI/UTZ5+uTeJH9lv/yUMiusZz10Mfm7fjLdbnJpu9LedMa2mqM5BVvWn3pjhfquu3aToigdJlNs4CBj6RW1uKIoPUn+2tv1IYE3zuRq64jptJeeLfnuW3V+8d5dsYGDYgMHHR0ZkDI7vCI+Vn1LUZSzH0ad++h97Rwx7Wi+bcvG4qL0eS/oxw5Pmja+9uxp2wa9mWNqbj7z/lvxYwKPhY4q/PLT3pRiWQQQQAABBBBAAIFuBUj+BtRwnM4igAACCCDgaQGSP0+Lsz4EEECgXwRI/nqZ/CmKcmb1G/mbPu52EO68QZ8mfx0mU1J4aGVivPM+2H3X7clfbzpjt4d2Z555762CrRu1b7llN7kx+Wu9XhMbOMjUZNR2UkwnTRtfnXpcnV+8d1fyzKkdJpOpubkyMT5uxGBjyWX13cu7Y069fj/j7Ha+2kCdyH37nwVb1iuKcrO2ttVwXZ3vlon8TR+nPBfeUlVZfyH/WOjIssOH3FKWIggggAACCCCAAAJ2BUj++mVYzUoRQAABBBAYKAIkfwNlT9FPBBBAoFcCJH+9T/4aiy7pQwJv1t7Qjr3FlWEle3dnLHgxKWzC+Y1r1XfzN32cFB4aPyYw5bnwsp/v3QpSJH8Fn27SjwlMnjHF6rou22v+as+ezlgYET9uRMKkkFOvr2ipqVbr2524cmDfiTnP2b5lamw8v3FtUniofuywzEVzmiuuiTbFe3clTRt/LHRkyd7d9+/22d5e+OVnSWETjoWOzHl9uVip8WpJ8vTJiVPGxo0YnDx9cvL0yVb3rrRdqd3OnHp9xcUv7l8TlrNqaeG/totlDdmZ6fOe148dnjI7vOZEilrQeKUkZ9XShInB8ROCTr/zwM02T0e9XvDpJrWloih2d1P+5vWZi+cmThl76o0V5z56/1joyKs/fKcoSltdXc6qpceeGh0/bkTGghfVK+FOzJ2dPH1ybOCgpLDQ5OmT1cjt4hefnnpjxZn33tIHP5k8c5p6+830eS8UbN2QPHNa/LgRuW//s62h3tKl9vbk6ZOPP/1UbOCg49MnJU+fXPLdv7VdTZgcUp2WrM4RyZ/6Uj922LW4/6ovi7/9Ouefr6ov1QlH89UG6sTZD6MubN+ivnTvRPz4IDXtK9iyPvMfc9xbn2oIIIAAAggggAACWgGSv14Nj1kYAQQQQAABXxcg+fP1Pcz2IYAAAncFSP56n/wpipKzaunFHdu0Q26R/OWtixaXUunHDlfTo+Jvv24qvaooSu25M0dHP3EjN0dRlJr01NjAQZe+2tHR1ladmhwXFNBUXqYWtE3+DDlZVccTTM1N7S0tp6PeOPnqArWx3Yn21taESSHXM9Ot3s1ZtTRr+aLWmpoOk8mQlSFuYlmTkaYfE1hfkN/e0pL79io1+bv6w3fHn36qqazUstLVb2pX6vrdPi3Jl73OVCboj0+fJLrXVl93dGSA8arlKXeNxUVHRz9Rceyo0t5uyMnSjwkUMqampsSp4y5s32JqbjI1N5Ud+VHdtLbGhuQZU64e3K/OERO2uyl/8/rT70Samoz6kMDSnw4asjLEbVFba2quHNh3s7ZWaW+/cmCffuwwU3OTKOLobp9HRz9xPeNEe2vr2eh3s5YtFI3T572QFDahqazU1NSUuWT+2TWr1S61VFXaveav4dLF2OGPaa/q0yZ/hpys2OGPNRYXqXUsDwWcNt7S1Qd/HM1/sJXlVfl/D+tDAhsvX7J9q5dzWmss1zXW5Z0t/fH76tTjZT8fPBY6spc1WRwBBBBAAAEEEEDAiQDJHwN9BBBAAAEEEHAiQPLnBIe3EEAAAd8RIPlzS/JXe+6Mfuxwk/H+nRtFPlR77owYlme88pJ6eZ92oJ65eG7xf/aI5C8u6PH21lbx7ok5z4n54qVt8qctYsnDxg7XzrE7fXl3TObiedq3WqqrYgMHiRhSOz9vXfTp1W+KOQ2FF9TkL3Px3KKvvxTzjSXFsYGD2urrxEup5E9RFNvOtN+8GT9uRO05y3Pmrh46kD7veVHZ8sQ+zd0ss1cuETLX4n5JCgtVOjpEM/W/Fz/fGjdicPr8Fzra2tSZYsJ2N+VvXi8ePpc8ffKN3JzmivL4cSOsllLa2+NGDK6/WCDmO0r+MpfMFw1q0lOTpo0X0+nzXlAfbledmqzdTXaTv8yFL8cGDirY9sB9Sov37oobMThhUkj8+KCjIwNK9u99oIcdHVnLF8UOf0zEzPffcjT/fgvLlCEnK2Xm1KsH9yc/O0Vcklj64/fqcftgW8ur49MnHQsdqf3NXrnEtpmYY7xaYnkmYklx5uJ5BVvWV8THHR01xFFj5iOAAAIIIIAAAgj0XoDkz3fG6mwJAggggAACfSBA8tcHqJREAAEEvE+A5M8tyZ+iKJmL52nvcnkvHyopFqP3zMVzrxzYJ6ZLf/z+xJznjj/9lOUem8FDL+/5WiR/x54arQ71c1Yt1d6A0Tb5a64oP7P6jeQZU5LCQxMnjzk6+gl1WUcTJqNRjdZEmxtncmOH/d02PMt5ffmFz+7dKrOtvk5N/pJnTlXv3GhqbIwNHKReKCab/Nl2RlGUc2vfE09MzPzHHDXfOvXGivgJQckzp4rfxKnjCr/8TFGUol07MxfPtbuxrYbriVPHaW+JqTaz2k2W5G/n54qiJM+cWnvudEtVZfyYQMtViTdvFmz7JGVWWFJ4aFJ4aOywv6thmKPk7/S79243asjJUq9sS5/3wpUf/iPWXl+QHxs4qP3mTfHSbvKnKMqN3Jy4oMfV264qimK55m/GlNbrNc2VFdVpyQmTQiqTjqlbVJORdix0VEtVpTpHTDiab9Usc/Hca3G/KIpyYftmy6WK7e05q5YaTmVZNVNfttRUt1RVan+t7nOrtlQURb3mT8zkmj8tDtMIIIAAAggggEBfCJD8ed+Ymx4hgAACCCDgRQIkf160M+gKAggg0HcCJH/uSv6un0xPmBSiXrTnKPkz5GTFjw9qKLwgxvmZi+aIvLAmPdXqmj/ts99SZoVVJui1pwYyF889v3Fte0uL5bKt7EwXL6W6+MWnOZHL1DoOr/lb/+G5te+JZsYrlsu2RLDk5Jo/Q3Zm4pSxamVXJqw6I64/S5gU0nSt/OjIgJs3DKJIwZb1eR9/YFvQ0TV/omXu2/+8+PlW26WsdpNt8qcPsSR/l77akT7/BdGHjrabcSMGi4sRLQXb2y3Xsd29E6la/+IXnzpK/rTX/MWPD1IXcZT8KYpyLHTU9YwTakvt3T4VRTnzwTu5b6/SvLs7a8U/1JfqRPFe+/PVBmIi9fmnq44nWKbb2y0H1YY1yTOmtDU2WDVTXyaFherHDtf+2l272v6B5/xt3cBz/lQZJhBAAAEEEEAAgb4QIPnru7EzlRFAAAEEEPABAZI/H9iJbAICCCDQvQDJn7uSP0VR0uc9f+X7exd4OUr+KpPijz/9VEeb5cIvy3P+Rgaoyd+95/yZTNVpyUdHDdFe9ZX71srzG9dqTw2kvjC99MfvFUXpaGvLffufLiZ/N2trLU90K7r/RLfslUvuP+cvJ0vc+dOQlZE4eYx4dFzB1o1q8nfl+/9on/OnvXeo8UpJXFBAS3WVtpPOp207oyhKUljoyWWvZK9crC7bcKlQP3Z4dVpyh8nU3tJScyJFpG4mozFxytiLn28VDzss//WwuoiiKKdXv1mw9YF7ZqrvaneTo+Qvf9O6M6vfEIsU79sTGzjofvKnKAmTQyriY9WCiqI4Sf6SwkLFc/5OvrpAe0NOJ8lf4tRx1anH1foi+bNsfmtrw6WLx5+ZqH2o5OXdMTmvL1cbqxOO5qsNxEThl59lvPKSiPqMJcVxIwZbHWlW7ZsrrjVdK9f+tl6vsWqjfZm/6ePU559pvV7TWHTpWOgo9ZpRbRumEUAAAQQQQAABBNwlQPLX/RiYFggggAACCPixAMmfH+98Nh0BBPxJgOTPjclfZdKxpPDQDpPJEsiZTOIJZ2IMf/9un+3teR9/kDIr7OSyV/LWf6jefLImPTVx6rgL2zfrxwQmz5hSmRSvHfwbS4rTIp7VBz+ZseBFMd+Qm5364oyMhRFZyxZe3vO1i8mfoij5m9erz/BTFKWtseH8+jVJYRP0YwIzFkY0V5SL+sX79qTMDs9YGFGw7RM1+eswmS7u2JY0bXz8hKCcVUut7jCZv3l9wuSQxKnj1GcBajfB7rRVZywR2udbYwMHWd2o05CVkbHgxfhxI+InBGWt+Iex9IqoZiwpzl655NhTo+PHB2kvg7NcGPf+WwVbN9hdqXY3OUr+WmqqT766IC1iZtayhcX79uhDArXJ37XYI0lhoYlTxqoJpZPkr2DbxpRZYfHjRpx+J9LU2Kh2yUnylxQ2oSo5UW1ZvHdXbOCg2MBBcUEBSWET8jd9rF5aarnr6Tf/OvXma2pjdcLRfLWBmOgwmQq//Cz1+aczF76csTCi8MvP4seNMJZctmrW45em5uYz778VPybwWOjIi1982uM6LIgAAggggAACCCDgigDJnz+N5tlWBBBAAAEEpAVI/qTJWAABBBAYiAIkf25M/hRFSZkdXv7fBy4+c2V87sk2LVWV+uAnm8pKPblSR+vqu85c2L7l5KsLRApru3Yv303p818o/Nd2227bmdPRcerN18TDER9419H8BxrxAgEEEEAAAQQQQMDXBEj+BuKonD4jgAACCCDgMQGSP49RsyIEEECgPwVI/tyb/Blys6/FHvHy8wflvx6+kZvjJZ3so840V1w7uXRB4tRxdoNYL99N10+mp0U8mzRtvPFKiZPdVJWSlDRtfObiuepFkKKxo/lOSvEWAggggAACCCCAgG8IkPz15+iadSOAAAIIIOD1AiR/Xr+L6CACCCDgDgGSP/cmf75xvoCtQAABBBBAAAEEEEAAgYEoQPLnjlEyNRBAAAEEEPBZAZI/n921bBgCCCCgFSD5I/kbiGc06DMCCCCAAAIIIIAAAgjYCpD8aUe7TCOAAAIIIICAlQDJnxUILxFAAAHfFCD5I/mzPV/AHAQQQAABBBBAAAEEEBiIAiR/vjluZ6sQQAABBBBwkwDJn5sgKYMAAgh4twDJH8nfQDyjQZ8RQAABBBBAAAEEEEDAVoDkz7vH3/QOAQQQQACBfhYg+evnHcDqEUAAAc8IkPyR/NmeL2AOAggggAACCCCAAAIIDEQBkj/PjKNZCwIIIIAAAgNUgORvgO44uo0AAgjICZD8eWHyZ2oyxgYOaqmqVM81tLe0ZK34R8KkkPPr16gzB+5E5pL5CZNC8j/5qI82YcOGDZs2beqj4pRFAAEEEEAAAQQQQMBrBUj+5MbDtEYAAQQQQMDPBEj+/GyHs7kIIOCvAiR/vUz+mkqv6oOHNldWuHHwb5v8VR1PSPSPcokAACAASURBVJgc0n7zphvX0r+lmiuuWdLNmmptN67FHslcPFdRlGOhI+svFqhvOZp/bu3qwp2fNxZd0o8drjZWFKWuri4gIKC8vFw7k2kEEEAAAQQQQAABBHxegOTPX0f2bDcCCCCAAAIuCZD8ucREIwQQQGCgC5D89TL5UxTlzOo38jd97MaTCLbJX9nPB0+8PMuNq/CGUkdHDWkovKDtiaOEz9F8R8mfoij//Oc/N27cqC3ONAIIIIAAAggggAACPi9A8jfQR+j0HwEEEEAAgT4VIPnrU16KI4AAAt4iQPLX++TPcs1ZSODN2htW5xGaystyVi09FjoqKSz08p6vxbsdJlNs4KCSvbszFryYFDbh/Ma16lLFe3clTRt/LHRkyd7dVnf7vHrowIm5s9WWYuLK9/9JnjlVP3Z45uJ5xqslYubNG4acVUv1Y4elRczM+/iD7JVLFEVxtNK2ujpLD58aHT9uRMaCF2vPnlZXUZefd3TUkIpjR1OeC0+aNl7UURSleO+urOWLCr/8LHn65IRJIZd3xyiKUvbzwZTZ4foxgceffqpg6wZxbaLxSklc0OOthuuiZnNlRdyIwU3X7l+Hpw8eWl9wXl2joiiOEj5H850kf4cOHQoNDdUWZxoBBBBAAAEEEEAAAZ8XIPnzlpE2/UAAAQQQQMArBUj+vHK30CkEEEDA3QIkf71P/hRFyVm19OKObdrzCO2trcenTyrY9kn7zZvNFeXJM6Zci/uvGsLlrYtWFOVmba1+7HCRt9VkpOnHBNYX5Le3tOS+vUqb/HWYTKejXj/9bqS2fumP3ydOHddw6WKHyVT87dcpz4Ur7e2KouS+tfLUm6+Zmpsbiy7Fjw/SJn+2K22tqblyYN/N2lqlvf3KgX36scNMzU1iLXX5ebHDHzvz/lvtra2KohhLisX84r279MFDi/futrzs6BCJY/kvP9flne1oa2upqU55Lrzo6y9F44xXXiret0dMX94dk7lkvpgW/02ZFaYGomJOU+nV6tRkEQG21depjR3Nv5GbU1+Q39ZQX/7rYbWxmDh//vz//d//NTc3W83nJQIIIIAAAggggAACPixA8ufuETP1EEAAAQQQ8CkBkj+f2p1sDAIIIOBIgOTPLclf7bkz+rHDTUajehKh6njCsdCRIo0Tl8rlvL5cTf5qz50RLTNeeans54OKouStiz69+k0xs6Hwgpr8VaUk6YOHJkwMNpZeUYsripL20rMl3317b05HhyU1vFigtLfHBT1+40yumH9u7Xva5M92pdqClmVHDFafrmdJ/gIHNVfcv0RPNC7eu+v4MxMfWPDBF4U7PxdbKq4FTH1xhng/5bnwa7FHtG0NWRn64KH6scONV+5dsKh9t5fTV69e/b//+7/Kyspe1mFxBBBAAAEEEEAAAQQGkADJn6ORL/MRQAABBBBAoKWlheSPwwABBBDwCwGSP7ckf4qiZC6eJ259Kc4LlHz376Ojn0ieOVX8Hn/6KXHFm7jxpnoJXebiuVcO7LNcNfj68gufbRLLttXXqcmfJSxsu5m9csm5j97XnnGIHx+UNG28Wj9hYnBNRlrr9ZrYwEFNZaWiZeGXn2mTP9uVtt+8WbDtk5RZYUnhoUnhobHD/q6mg3X5eXFBj2vXKKaL9+46+eoCq/mGnKyTSxccf2ZiUnho/PigrBX/EA1MTUZ9SGBD4YX6gvN3Lyh84Aq89PkvXPx8q1Upd73kmj93SVIHAQQQQAABBBBAYAAJkPz5xTCejUQAAQQQQKCnAiR/PZVjOQQQQGBACZD8uSv5u34yPWFSiLg3pqIoVccTUmZOtT1H4Cj5y1v/4bm174n2xisl2uRPUZQr3/8nY8GL2mppLz0rbh+qndlhMsWNGOzomj/b5O/SVzvS579w84ZB5ItxIwbXnrv3qD/xnD9tcTEtnvOnnd/e0qIPHnot7helo0NRlMIvP8tavkhtcDb63YJtG/M3r7dKLhVF0Y8JVINGtb27Jn788ccJEya4qxp1EEAAAQQQQAABBBAYEAIkfwNqOE5nEUAAAQQQ8LQAyZ+nxVkfAggg0C8CJH/uSv4URUmf9/yV7/8jzgi0t7Qcf2bi5d1ftbe0dJhM9QXnDdkn1bt92oZwhqyMxMljLI/cU5SCrRutkr/Snw6eeHmW9lzD1YP7U2aFNRZdUhSlrb6u7MiPHSaToiin3lhx7zl/l62f82e70vxN686sfkOULd63JzZwUA+Sv7a6uthhfxd37LxZeyN5xhRt8mfIzU6YFJIwMVjNI9WtODpqiHpzUXWmuyZWrVq1YcMGd1WjDgIIIIAAAggggAACA0KA5K9fhtWsFAEEEEAAgYEiQPI3UPYU/UQAAQR6JUDy58bkrzLpWFJ4qEjgFEVpKr166vUVCROD9WOHnZg7uzo12UnyZ3kW4L49KbPDMxZGFGz7xCr5Kzt8KC3iWatzDVe+/0/KrLD4MYGJU8aeee8t8UzBVsP17JVL9GOHpUXMzFsX7fxuny011SdfXZAWMTNr2cLifXv0IYE9SP4URbn6w3fJM6dlLp536o0V5zeu1SZ/iqKkzJyaPGOKVecVRYkLCmi4VGg7v/dz6urqAgICysutH1LY+8pUQAABBBBAAAEEEEDAmwVI/no1PGZhBBBAAAEEfF2A5M/X9zDbhwACCNwVIPlzY/JnSblmh5f/97DbzwXUZKTFjw9qq6+Tqlz09Zci+ZNayu2NT766oOjrL63K1l8siB32d3GNo9VbvX+5YcOGTZvuPTSx99WogAACCCCAAAIIIIDAQBEg+WOgjwACCCCAAAJOBEj+nODwFgIIIOA7AiR/7k3+DLnZ12KPuP28QEdb29nod5PCQs+vX+N6cW9I/mrPnT46akhLdZW225lL5idPn1y0a6d2JtMIIIAAAggggAACCCDQSwGSP98Zq7MlCCCAAAII9IEAyV8foFISAQQQ8D4Bkj/3Jn+9HKi7d/F+T/7S57+QOGXs1UMH3LtdVEMAAQQQQAABBBBAAAG7AiR/3jfmpkcIIIAAAgh4kQDJnxftDLqCAAII9J0AyZ8PJ392zwUwEwEEEEAAAQQQQAABBHxVgOSv78bOVEYAAQQQQMAHBEj+fGAnsgkIIIBA9wIkfyR/vnrWg+1CAAEEEEAAAQQQQMDfBEj+uh8D0wIBBBBAAAE/FiD58+Odz6YjgIA/CZD8kfz529kQthcBBBBAAAEEEEAAAV8VIPnzp9E824oAAggggIC0AMmfNBkLIIAAAgNRgOSP5M9Xz3qwXQgggAACCCCAAAII+JsAyd9AHJXTZwQQQAABBDwmQPLnMWpWhAACCPSnAMkfyZ+/nQ1hexFAAAEEEEAAAQQQ8FUBkr/+HF2zbgQQQAABBLxegOTP63cRHUQAAQTcIUDyR/Lnq2c92C4EEEAAAQQQQAABBPxNgOTPHaNkaiCAAAIIIOCzAiR/Prtr2TAEEEBAK0Dy14Pkr4ofBBBAAAEEEEAAAQQQQMArBaQGOG13fzK7+xHNcnNzCwsLS0tLq6urDQZDfX19Q0OD0WhsamqyHVdqR51MI4AAAggggICXCJD8ecmOoBsIIIBA3wrYjtCampqMRmNDQ0N9fb3BYKiuri4tLS0sLMzNzZUaQ9IYAQQQQAABBBBAAAEEEEDAmwVI/vp2vE11BBBAAAEEvEyA5M/LdgjdQQABBPpGgOTPm8fh9A0BBBBAAAEEEEAAAQQQ6DsBkr++GWdTFQEEEEAAAS8VIPnz0h1DtxBAAAH3CpD89d0omsoIIIAAAggggAACCCCAgDcLkPy5d3xNNQQQQAABBLxcgOTPy3cQ3UMAAQTcI0Dy583jcPqGAAIIIIAAAggggAACCPSdAMmfe8bVVEEAAQQQQGCACJD8DZAdRTcRQACB3gmQ/PXdKJrKCCCAAAIIIIAAAggggIA3C5D89W48zdIIIIAAAggMMAGSvwG2w+guAggg0DMBkj9vHofTNwQQQAABBBBAAAEEEEBA5HMu/leKi+SvZ+NolkIAAQQQQGCACpD8DdAdR7cRQAABOQGSP6mBMY0RQAABBBBAAAEEEEAAAQ8LuJj5iWZSfSP5kxs/0xoBBBBAAIEBLkDyN8B3IN1HAAEEXBMg+ZMaGNMYAQQQQAABBBBAAAEEEPCwAMmfa6NbWiGAAAIIIIBANwIkf90A8TYCCCDgGwIkfx4etLM6BBBAAAEEEEAAAQQQQEBKgOTPN0bfbAUCCCCAAAL9LkDy1++7gA4ggAACnhAg+ZMactMYAQQQQAABBBBAAAEEEPCwAMmfJ8bGrAMBBBBAAAE/ECD584OdzCYigAACLS0kfx4etLO6rq4uEBBAAAEEEEAAAQQQQMB1AZI/xu4IIIAAAggg4BYBkj+3MFIEAQQQ8HYBkj/Xx9u0dIvAhQsXfvnlF7eUoggCCCCAAAIIIIAAAv4gYDf5O3DggN35UiCiQmZ3P6JZbm5uYWFhaWlpdXW1wWCor69vaGgwGo1NTU2240pvHwnTPwQQQAABBPxSgOTPL3c7G40AAv4nYDtCa2pqMhqNDQ0N9fX1BoOhurq6tLS0sLAwNzdXagxJYwSEQHl5+UTNz7hx43Q63aFDh/BBAAEEEEAAAQQQQAABVwRsE74D//uxfcuVgmobkj//OwfAFiOAAAII+LUAyZ9f7342HgEE/EeA5E8d9DLhGYGKiopNmzZxz0/PaLMWBBBAAAEEEEAAAR8QsIr3/pf63ftfq3eltpfkz3/G/mwpAggggAACLS0tJH8cBggggIBfCPhM8ldbW3v06NHjx4/fuHGj27Hu1atXk5OTY2NjOzo6um1MA/cKGI1G9xakGgIIIIAAAggggAACvi2gzfasYj/xUttAioLkzy+G/WwkAggggAAC/xMg+fufBP+LAAII+LSALyV/KSkp2lFuS0tLZmZmfHz8sWPHcnJy2tratO/+8ccfJH9aEKYRQAABBBBAAAEEEEDAOwW0wV6301KbQPLn08N9Ng4BBBBAAAFrAZI/axFeI4AAAj4p4MPJ361bt1paWjrv/pSUlCQlJWnHwCR/Wg1H02lpadOnT3f0rt35GRkZMTExkZGRqampdht4cmZBQcHEiRM9uUbWhQACCCCAAAIIIICA2wW6Tfu0DaTWTvLnk8N8NgoBBBBAAAFHAiR/jmSYjwACCPiUgA8nf9oRb1VVVWxs7O3bt9WZjpK/oqKijIwMtZk/TyQlJS1ZsuQvf/lLDxAURQkNDTUYDF988cXgwYN1d38WL14cHR29dOnSv//97zqdrqqqqgeVXV+ko6Pj6aefnjBhguuL0BIBBBBAAAEEEEAAAS8U0AZ73U5L9Z/kz6eG92wMAggggAAC3QmQ/HUnxPsIIICATwj4fPKXmJgYHx8fGxubn5+vHQM7Sv7y8vL0er22pT9PHz58uGfJn9ls3rhxY0xMjNlsXrlypU6ne/TRR7u6ugRmY2Pj6NGj+zr527JlyzfffEPy588HMNuOAAIIIIAAAgj4hkC3aZ+2gdQmk/z5xLCejUAAAQQQQMBVAZI/V6VohwACCAxoAZ9P/jo7O00mU1FRUUNDg3YM7Cj507Zh+siRIz1O/r799tuoqCiz2bx69WqdTjd48GDhWVFRYTabY2Ji+jT5S0xMPHHixJEjR0j+OIwRQAABBBBAAAEEBrqANtjrdlpqY0n+BvRwns4jgAACCCAgK0DyJytGewQQQGBACvh88ifGvV1dXXq9XlEUdRhM8qdSOJmQTf5aWlqioqKio6PXrFmzaNGiZcuW2SZ/H374odlsbm5uvnXrlpNV9+aturq67du3m81m2+Tv0KFDoaGhf/nLX8QNSHU6nd0HAaqXJ/amGyyLAAIIIIAAAggggIBbBKTyOak1SlXOzc0tLCwsLS2trq42GAz19fUNDQ1Go7Gpqcl2XDkgh8d0GgEEEEAAAV8XIPnz9T3M9iGAAAJ3BWxHaE1NTUajsaGhob6+3mAwVFdXl5aWFhYW5ubmSo0hPdy4trY2JSXF0Ur/+OOPo0eP1tfXqw18IPnzQDollfw1NTWFhITs37/fbDa3tbU98sgj0dHRVslfZmbmsGHD1L3QFxN//vnnmjVrfvvtN9vkLy8vLyUlJTIycufOnSdOnHj++eevXr1aW1tr1Y07d+7ExMQ0NjZazeclAggggAACCCCAAAL9IiCVz0n1UKoyyR9nERBAAAEEEBjoAiR/A30P0n8EEEDAJQEfTv6qq6sbGhp+//33W7duFRQU6PX6zs5OdRjsKPkrKipKT09Xm3nzRENDw65du27fvt13nZRK/qKiombOnCk6oyjKQw89tGfPHjX5++tf/7p06dKAgIAhQ4b0XYfNZvPevXuLiorEKmyv+evs7BwxYoTRaPzmm28OHTqk9mTNmjUT//fz1FNPBQQETJgwQcSHahsmEEAAAQQQQAABBBDoFwGpfE6qh1KVSf5cGmPTCAEEEEAAAS8WIPnz4p1D1xBAAAH3Cfhw8ldVVZWWlqbX648dO5aVldXU1KQdAztK/vLy8vR6vbalV03PmDHjf/nUxNDQ0EcffTQyMrLveiiV/AUEBKhZWk5Ojk6nq66uVpM/8Zw/o9HY1w/eCw8PV+/kqU7s3LlTKB0+fHjOnDlms/npp582GAyO6LZv367Gh47aMB8BBBBAAAEEEEAAAc8ISOVzUl2Sqkzy576BOJUQQAABBBDoHwGSv/5xZ60IIICAhwV8JvlraGhITExMTU21vXmj7dC3tLQ0NTU1ISFB++Q/22ZePufWrVsffvhhc3Nz3/XT9eTPaDTqdLq8vDzRmUWLFkVERIjp1atX63Q6kfyZzeYtW7aI+X0UrXVpfn7++efx48d3dXX9+eefZrO5q6tr6tSpP//8c0VFxfDhw81mc0tLi63enTt3WltbbeczBwEEEEAAAQQQQACBfhGQyuekeihVmeTPw6N1VocAAggggIDbBUj+3E5KQQQQQMAbBXwm+ZMa3/pG45aWljt37vTptnz33XePPPKIiM2cr6irq2vo0KHnzp0zm815eXmjR49Wn6polfyJqLKtrW3FihXOa/b+Xe3dPhsaGubOnTtixIjOzs6EhIQnnnji+PHjaWlpvV8LFRBAAAEEEEAAAQQQ6FMBqXxOqidSlUn+vHFIT58QQAABBBCQESD5k9GiLQIIIDBgBUj+pAbGftU4Ozs7LCxMp9PFxMQ4uTGmapKYmLh8+fIdO3ZERkaWlZWp81977TWdTve3v/2tq6tLzGxtbX3llVc2btyotumjCW3yl5aWNmzYsNOnT5vN5vLy8qCgoLfeekvtUh91gLIIIIAAAggggAACCPReQCqfk1qdVGWSvwE77qfjCCCAAAII3BMg+eNQQAABBPxCgORPamDsSuMNGzbodLqXX3551YM/L7/88vvvv+9KBV9q88UXXwwePFg8b2/ZsmXbtm178803hwwZotPpYmNjvXBLDx48OHr06IyMDC/sG11CAAEEEEAAAQQQ8E8BqXxOikiqMsmfX5wjYCMRQAABBHxagOTPp3cvG4cAAgj8T4DkT2pg7Erj6urqhx9+WH2anbrI5s2bL1++rL6UnYiLixs3bpyI0ObMmbNu3boJEya8++671dXVsqVo70Rg+fLlOp1u69atTtrwFgIIIIAAAggggAACnhSQyuekOiZVmeTvf8No/hcBBBBAAIGBKkDyN1D3HP1GAAEEpARI/qQGxi42Xrx48bBhw37//Xe1fWdn55IlS9SX6sTt27ft3kizsrJSbaNO7N27VyR/RUVFZrN53bp1Op0uODi4s7NTbcNELwUaGhr++9//mkymXtZhcQQQQAABBBBAAAEE3CUglc9JrVSqMsmf1FibxggggAACCHihAMmfF+4UuoQAAgi4X4DkT2pg7GLjrKwsnU6n1+vV9rF3f9SX6kRKSsqoUaMqKirUOWaz+YcffggJCbl165Z2ptlsjo2NFcnf1atXzWbzkSNHxMuLFy9ateRlzwTS09ODgoJ0Ot3q1at7VoGlEEAAAQQQQAABBBBwu4BUPie1dqnKJH/uH5BTEQEEEEAAAc8KkPx51pu1IYAAAv0kQPInNTB2vfGkSZMiIiLU9kuXLnV0Zd7evXu14d+BAwe0L9UKtsnfv//9b51O97e//c1oNGqb+cb07du3Ox383Llzp++2MSoqiuSv73ipjAACCCCAAAIIINADAal8Tqq+VGWSv34atbNaBBBAAAEE3CZA8uc2SgohgAAC3ixA8ic1MHa98YEDB3Q6XVlZmdlsLikpsX3sn7bUv//9b5H27d+/Pygo6Nq1a9p31Wn1mr9Tp05lZ2eHhIRMnTo1IyNDbeBLExEREeKKRtv/RkdH992WRkdHk/z1HS+VEUAAAQQQQAABBHogIJXPSdWXqkzy581De/qGAAIIIICAKwIkf64o0QYBBBAY8AIkf1IDY9cbd3R0BAQErFu3zmw2r1mz5vr1686X3bNnzxNPPDFixAgRFtptrCZ/W7Zs+fDDDwMCAhYuXJibm2u3sZPkzCevEbSL0IOZJH89QGMRBBBAAAEEEEAAgT4VkMrnpHoiVZnkb8CP/9kABBBAAAG/FyD58/tDAAAEEPAPAZI/qYGxVON169YNGTLEaDRGRkZ2u+D+/fuHDBkycuRIq2f+aRdUkz/xnL+0tDSdTvfQQw+lp6drm4npzs5OxcHPn3/+adtenWN7jZ12jtpMO6FtIDutrdPLadlVq+216yX502owjQACCCCAAAIIIOANAlL5nFSHpSqT/PnHSQK2EgEEEEDAlwVI/nx577JtCCCAgCpA8ic1MJZqXFVV9fDDD8+ePbvbG3IeOHAgKCiovLxcve2n3RVZJX9dXV2PPvqoTqdbtGiR3fY9m5nm9MduTadLdPOm3YJms9nJNYuO7vbZzZocv63tA8mfVoNpBBBAAAEEEEAAAW8QkMrnpDosVZnkTx1HM4EAAggggMAAFSD5G6A7jm4jgAACcgIkf1IDY9nGixYtGjdunPNr7NTYTxTfu3eveOaf7bqskr8///zzr3/9q06nW7ZsmW3jgT7HyTWLnZ2dfbd1JH99Z0tlBBBAAAEEEEAAgZ4JSOVzUquQqkzyJzfYpjUCCCCAAALeJ0Dy5337hB4hgAACfSBA8ic1MJZtfPLkyd27dztZKjU1VVztp22zb9++4ODgW7duaWeazeb9+/eLG1Tm5+ebzebs7GydTvfXv/7V0aP+rBbnpSsCIvl77733XGlMGwQQQAABBBBAAAEEPCAglc9J9UeqMslfH4zIKYkAAggggIBHBUj+PMrNyhBAAIH+EiD5kxoYu71xZ2dndXW1bdmysjKrmXq9PjQ0VCR/zz777Pr168PDw5ctW3bhwgWrll7yMiMjIyYmJjIyMjU11Uu65KQbLS0tmzdvrqmpEcnfli1bnDTmLQQQQAABBBBAAAEEPCkglc9JdUyqMslffw3bWS8CCCCAAALuEiD5c5ckdRBAAAGvFiD5kxoY01hWQFGU0NBQg8GgLuj83qdqMw9PHDt2TKfT/fTTT5GRkTqdLjs728MdYHUIIIAAAggggAACCDgSkMrnHBWxO1+qMsmfV4/t6RwCCCCAAAIuCJD8uYBEEwQQQGDgC5D82R0AM9ONAhs3boyJiREFOzo6fv31VzcWd1epW7duRUVFbdq0aebMmQcOHHBXWeoggAACCCCAAAIIINB7Aal8Tmp1UpVJ/gb+CQC2AAEEEEDA3wVI/vz9CGD7EUDATwRI/qQGxjTugcC3334bFRVlNpsLCgqef/75M2fO9KAIiyCAAAIIIIAAAggg4LcCUvmclJJUZZI/PzlLwGYigAACCPiwAMmfD+9cNg0BBBC4L0DyJzUw9rfGnZ2dn3766datW999993CwkLXN7+lpSUqKio6OnrNmjWLFi1atmzZ2bNn586dO2jQoNWrVxuNRtdLuaVlbW3t2rVrd+zYsWrVqo6ODrfUpAgCCCCAAAIIIIAAAp4RkMrnpLokVZnk7/5AmikEEEAAAQQGpgDJ38Dcb/QaAQQQkBQg+ZMaGPtV487OzpkzZ+r1erPZPGfOnK+++srFzW9qagoJCdm/f7/ZbG5ra3vkkUeio6PNZvMXX3wxd+5cF4u4sdm1a9dCQ0MrKip+++23wYMH5+XlubE4pRBAAAEEEEAAAQQQ6GsBqXxOqjNSlUn+JEfbNEcAAQQQQMDrBEj+vG6X0CEEEECgLwRI/qQGxn7V+PPPP58zZ47Y5Orq6jt37ri4+VFRUTNnzhSNFUV56KGH9uzZYzabX3rppZ07d7pYxI3NXnrppX/961+i4LVr19xYmVIIIIAAAggggAACCHhAQCqfk+qPVGWSv74YklMTAQQQQAABTwqQ/HlSm3UhgAAC/SZA8ic1MParxkFBQQcPHuzBJgcEBBw6dEgsmJOTo9Ppqqurf/vtt0cfffTs2bM9KNibRSoqKnQ6XUVFRW+KsCwCCCCAAAIIIIAAAv0oIJXPSfVTqjLJX7+N21kxAggggAACbhIg+XMTJGUQQAAB7xYg+ZMaGPtP45aWFp1Ol56eLrvJRqNRp9Opd9RctGhRRESE2WzOzs7+29/+9vvvv8sW7GX7xMREnU7322+/9bIOiyOAAAIIIIAAAggg0F8CUvmcVCelKpP8effgnt4hgAACCCDQvQDJX/dGtEAAAQR8QIDkT2pg7D+N79y588QTT6xdu/bOnTttbW2xsbGdnZ2ubH5XV9fQoUPPnTtnNpvz8vJGjx5dX19vNpu3b98+Y8aMxMTErq4uV+q4q01hYaFOpxNPKzQYDImJie6qTB0EEEAAAQQQQAABBDwjIJXPSXVJqjLJnw+cAWATEEAAAQT8XIDkz88PADYfAQT8RYDkT2pg7FeNk5KSgoODw8LCPv7447a2Nte3PTExcfny5Tt27IiMjCwrKxMLfvHFv/h7CAAAIABJREFUF1OmTCktLXW9jrtafvrpp0OHDp07d+4333zzxx9/uKssdRBAAAEEEEAAAQQQ8IyAVD4n1SWpyiR//nKagO1EAAEEEPBdAZI/3923bBkCCCCgESD5kxoY0xgBBBBAAAEEEEAAAQQQ8LCAVD4n1TepyiR/mpE0kwgggAACCAxIAZK/Abnb6DQCCCAgK0DyJzUwpjECCCCAAAIIIIAAAggg4GEBqXxOqm9SlUn+ZIfbtEcAAQQQQMDbBEj+vG2P0B8EEECgTwRI/qQGxjRGAAEEEEAAAQQQQAABBDwsIJXPSfVNqjLJX5+MySmKAAIIIICABwVI/jyIzaoQQACB/hMg+ZMaGNMYAQQQQAABBBBAAAEEEPCwgFQ+J9U3qcokf/03cGfNCCCAAAIIuEeA5M89jlRBAAEEvFyA5E9qYExjdwl0dXW5qxR1EEAAAQQQQAABBBDwbQGpfE6KQqoyyZ+Xj+7pHgIIIIAAAt0KkPx1S0QDBBBAwBcESP6kBsY0dpdAQ0PDrl27bt++7a6C1EEAAQQQQAABBBBAwFcFpPI5KQSpyiR/vnAKgG1AAAEEEPBvAZI//97/bD0CCPiNAMmf1MCYxr0RmDFjxsT//YSGhj766KORkZG9KciyCCCAAAIIIIAAAgj4g4BUPicFIlWZ5M9vzhOwoQgggAACPitA8uezu5YNQwABBLQCJH9SA2Mau0vg1q1bH374YXNzs7sKUgcBBBBAAAEEEEAAAV8VkMrnpBCkKpP8aYfSTCOAAAIIIDAQBUj+BuJeo88IIICAtADJn9TAmMbuEmhpablz5467qlEHAQQQQAABBBBAAAEfFpDK56QcpCqT/EmPt1kAAQQQQAABLxMg+fOyHUJ3EEAAgb4RIPmTGhjTGAEEEEAAAQQQQAABBBDwsIBUPifVN6nKJH99MyinKgIIIIAAAp4TIPnznDVrQgABBPpRgORPamBMYwQQQAABBBBAAAEEEEDAwwJS+ZxU36Qqk/z148idVSOAAAIIIOAWAZI/tzBSBAEEEPB2AZI/qYGxHzZ+5plnHnrooZUrV6568GfKlClxcXEuguTn58+fP19392fkyJHR0dHvvPPO1KlTdTrdG2+84WIRqWZtbW3BwcF1dXVSS9EYAQQQQAABBBBAAAEvFJDK56T6L1WZ5M/bh/f0DwEEEEAAge4ESP66E+J9BBBAwCcESP6kBsZ+2Pjw4cM6nS4zM9Nq2//xj3/8/vvvVjOdvCwrKxPJ386dO9Vm//rXv/oo+Xvvvfd0Oh3Jn0rNBAIIIIAAAggggMDAFZDK56Q2U6oyyZ9PnANgIxBAAAEE/FqA5M+vdz8bjwAC/iNA8ic1MPbDxp2dncOGDVu6dKl22y9durRt2zbtnG6n6+rqRPK3Z88e0biysvL333+Pjo7udlnZBr/++qsILEn+ZOlojwACCCCAAAIIIOCFAlL5nFT/pSqT/PnPiQK2FAEEEEDAVwVI/nx1z7JdCCCAwAMCJH9SA2P/bLxt27ZHHnlEm6J98MEHBoNBSsMq+auoqNi7d6/ZbJat0+1Ka2pqdu7caTAYuOavWysaIIAAAggggAACCAwIAal8TmqLpCqT/D0wluYFAggggAACA1CA5G8A7jS6jAACCMgLkPxJDYz9s3Ftbe1f/vKXHTt2iM1va2tbtWqVLIU2+bt58+bSpUtF8ue8zu3btzsd/Ny5c8d22a6urjVr1vz++++2yd/Zs2dnzZo1aNAgcemhTqd76KGHGhsbRZE///zzxx9/nDNnzrBhwy5evGhbmTkIIIAAAggggAACCPSXgFQ+J9VJqcokf/IDbpZAAAEEEEDAuwRI/rxrf9AbBBBAoI8ESP6kBsZ+2/i1114bNWqUCNv27dtn+9i/bmXU5G/69Onh4eE6nc6V5C8iIkIN6qwm7N4m9JtvvikrKxOXEmqv+auuro6Pj9+1a9err7565cqV8ePHX758+dq1a2q3169fHxMT09XV9cwzz0RFRanzmUAAAQQQQAABBBBAoN8FpPI5qd5KVSb566NROWURQAABBBDwmADJn8eoWRECCCDQnwIkf1IDY79tfPbsWZ1Od/z4cbPZvHjx4j///NMRxapVq1599VXbd9XkTzznb/v27a4kf7Z1nMzJz88/ePCgaGB7zZ/oeWJi4oULFyIjI7V1Lly4MHnyZDHntddeW7ZsmfZdphFAAAEEEEAAAQQQ6F8BqXxOqqtSlUn++nPozroRQAABBBBwhwDJnzsUqYEAAgh4vQDJn9TA2J8bh4eHL1iwIDc399tvv3Xi8NFHH7333nu2DaySv8bGRpH8tbe3V1VV2bbvwZx169ZZXReo0+nmzp0rSlVXVz/++OO//fbb+vXrjxw5oq3/5ptvbtmyRcyZMmWKel9TbRumEUAAAQQQQAABBBDoLwGpfE6qk1KVSf68fnxPBxFAAAEEEOhGgOSvGyDeRgABBHxDgORPamDsz41//vnnhx56aM6cOa2trT1wsEr+zGZzc3Oz2Wz+4osvzp4966ig1N0+//jjj67//VRVVel0OoPB8Mcff4ji0dHRb775ptlsHjVqVHl5uboVd+7cCQgIyMjIMJvNly5devTRR6urqx31h/kIIIAAAggggAACCHheQCqfk+qeVGWSP984CcBWIIAAAgj4swDJnz/vfbYdAQT8SIDkT2pg7M+NOzs7n3zyyXfeeadnCKWlpeKCvJ07d6oVkpOTH330UZPJpM6xmujs7FQc/HR2dlo11r7U3u3z9u3bH3300SOPPFJUVNTc3KzT6Q4ePPjjjz+K9gUFBQ8//LDJZPr9999nz54tbkaqLcU0AggggAACCCCAAAL9KyCVz0l1VaoyyZ8fnSlgUxFAAAEEfFSA5M9HdyybhQACCDwoQPInNTD288Zbt269ePFiDxAKCgrmzZsnkr/Ro0d/8sknH3/88ezZs3U63YQJE3pQsNtFtMlfY2PjsGHDdu3aZTab//jjj2nTps2ePbu+vl4UiYmJCQoK2rlz5/vvvx8bG9ttZRoggAACCCCAAAIIIOBhAal8TqpvUpVJ/h4cTPMKAQQQQACBgSdA8jfw9hk9RgABBHogQPInNTCmse8JzJ8/f+PGjb63XWwRAggggAACCCCAgM8ISOVzUlstVZnkrwcjbhZBAAEEEEDAqwRI/rxqd9AZBBBAoK8ESP6kBsY09jGB27dvP/bYY8ePH/ex7WJzEEAAAQQQQAABBHxJQCqfk9pwqcokf301LKcuAggggAACnhIg+fOUNOtBAAEE+lWA5E9qYExjHxOoqqp65ZVXmpqafGy72BwEEEAAAQQQQAABXxKQyuekNlyqMslfv47dWTkCCCCAAAJuECD5cwMiJRBAAAHvFyD5kxoY0xgBBBBAAAEEEEAAAQQQ8LCAVD4n1TepyiR/3j/Ap4cIIIAAAgg4FyD5c+7DuwgggICPCJD8SQ2MaYwAAggggAACCCCAAAIIeFhAKp+T6ptUZZI/HzkLwGYggAACCPixAMmfH+98Nh0BBPxJgORPamBMYwQQQAABBBBAAAEEEEDAwwJS+ZxU36Qqk/z506kCthUBBBBAwDcFSP58c7+yVQgggICVAMmf1MCYxggggAACCCCAAAIIIICAhwWk8jmpvklVJvmzGk3zEgEEEEAAgQEnQPI34HYZHUYAAQR6IkDyJzUwpjECCCCAAAIIIIAAAggg4GEBqXxOqm9SlUn+ejLkZhkEEEAAAQS8SYDkz5v2Bn1BAAEE+kyA5E9qYEzj3gt0dXX1vggVEEAAAQQQQAABBBDwHwGpfE6KRaoyyV+fjcspjAACCCCAgIcESP48BM1qEEAAgf4VIPmTGhjTuPcCFy5c+OWXX3pfhwoIIIAAAggggAACCPiJgFQ+J2UiVZnkr38H76wdAQQQQACB3guQ/PXekAoIIIDAABAg+ZMaGNO4BwLl5eUTNT/jxo3T6XSHDh3qQSkWQQABBBBAAAEEEEDADwWk8jkpH6nKJH8DYIRPFxFAAAEEEHAqQPLnlIc3EUAAAV8RIPmTGhjTuPcCFRUVmzZt4p6fvZekAgIIIIAAAggggICfCEjlc1ImUpVJ/nzlNADbgQACCCDgvwIkf/6779lyBBDwKwGSP6mBMY17L2A0GntfhAoIIIAAAggggAACCPiPgFQ+J8UiVZnkz6/OFbCxCCCAAAI+KUDy55O7lY1CAAEErAVI/qQGxjRGAAEEEEAAAQQQQAABBDwsIJXPSfVNqjLJn/VwmtcIIIAAAggMNAGSv4G2x+gvAggg0CMBkj+pgbG/NU5LS5s+fbrUVmdkZMTExERGRqampkotSGMEEEAAAQQQQAABBBCwKyCVz9mt4GimVGWSvx6NuVkIAQQQQAABLxIg+fOinUFXEEAAgb4TIPlzNAZmflJS0pIlS/7yl7/0gEJRlNDQUIPB8Pnnnw8aNEh39+fdd9+NjIycNGnSp59+euvWrR6UZREEEEAAAQQQQAABBPxQQCqfk/KRqkzy13cDcyojgAACCCDgGQGSP884sxYEEECgnwVI/qQGxv7W+PDhwz1L/sxm88aNG2NiYsxm89KlS3U6XUBAgNALDw/X6XSvvfaav2GyvQgggAACCCCAAAII9ExAKp+TWoVUZZK/fh69s3oEEEAAAQR6LUDy12tCCiCAAAIDQYDkT2pg7G+Njxw50uPk79tvv42KijKbzatXr9bpdIGBgULvnXfe0el0jz32mL9hsr0IIIAAAggggAACCPRMQCqfk1qFVGWSv4EwxKePCCCAAAIIOBMg+XOmw3sIIICAzwiQ/EkNjL2hcVdXl8e6IZv8tbS0REVFRUdHr1mzZtGiRcuWLbNN/pYsWaLT6Z555hmPbYXdFXmS0W4HmIkAAggggAACCCCAgIsCUvmcizVFM6nKJH8+cx6ADUEAAQQQ8FsBkj+/3fVsOAII+JcAyZ/UwNgbGl+4cOGXX37xTE+kkr+mpqaQkJD9+/ebzea2trZHHnkkOjpaTf6GDh1648aNw4cP/+1vf5s/f35FRYVnNsHuWu7cuRMTE9PY2Gj3XWYigAACCCCAAAIIIOBVAlL5nFTPpSqT/PnXyQK2FgEEEEDAFwVI/nxxr7JNCCCAgI0AyZ/UwLhfGpeXl0/U/IwbN06n0x06dMgDnZFK/qKiombOnCl6pSjKQw89tGfPHjX5e+yxx3bv3r18+fKhQ4e+9dZb169f90D/tatYs2aNqvjUU08FBARMmDDht99+07ZhGgEEEEAAAQQQQAABLxSQyuek+i9VmeTPZjzNDAQQQAABBAaYAMnfANthdBcBBBDomQDJn9TA2BsaV1RUbNq0yTM3q5RK/gICAtQ8MicnR6fTVVdXq8mf+py/Tz75RKfTPfnkk3V1df3ouX379qKion7sAKtGAAEEEEAAAQQQQMBFAal8zsWaoplUZZK/ng26WQoBBBBAAAHvESD58559QU8QQACBPhQg+ZMaGHtDY6PR6LFuuJ78GY1GnU6Xl5cn+rZo0aKIiAgxvXr1ap1OpyZ/Z8+e1d392bVrl8c2xGpFd+7caW1ttZrJSwQQQAABBBBAAAEEvFNAKp+T2gSpyiR/fTgypzQCCCCAAAIeESD58wgzK0EAAQT6W4DkT2pg7G+Nv/vuu0ceeeTPP//sdsO7urqGDh167tw5s9mcl5c3evTo+vp6sZSj5G/fvn3dlqUBAggggAACCCCAAAIISOVzUlxSlUn++nv4zvoRQAABBBDorQDJX28FWR4BBBAYEAIkf1IDY79qnJ2dHRYWptPpYmJiDAZDt9uemJi4fPnyHTt2REZGlpWVqe1XrFih0+kee+wxcYfSzz77TKfTjR49urGxUW3DBAIIIIAAAggggAACCDgSkMrnHBWxO1+qMsnfgBjj00kEEEAAAQScCJD8OcHhLQQQQMB3BEj+7A6AezBzw4YNOp3u5ZdfXvXgz8svv/z+++/3oKBY5OjRo6GhoeL2mE8//fTatWsjIyODgoJ0Ot1PP/3U47IeW/DLL78cPHiw6P9rr732/vvvT5o0ae3atTdu3PBYH9QVHT58eNGiRRs2bHjvvfc6OjrU+UwggAACCCCAAAIIIODNAlL5nNSGSFUm+fOdEwFsCQIIIICAvwqQ/Pnrnme7EUDAzwRI/qQGxk4aV1dXP/zww1u2bLFqs3nz5suXL1vNlHp54MABkZyJe2mazeY7d+4sWLDA9eSvrq7u9u3bUiv1vcZpaWkPP/xwYmLiH3/88eSTTy5atMj3tpEtQgABBBBAAAEEEPBJAal8TkpAqjLJn5+dLWBzEUAAAQR8UIDkzwd3KpuEAAII2AqQ/EkNjJ03Xrx48bBhw37//Xe1WWdn55IlS9SX6sTt27ft3j+zsrJSbaNOxMbGiuSvsLDQbDY3NTW1tbWdP3/e9eRvwoQJxcXFakH/nAgPD9fpdFeuXDGbzbNmzdLpdBcvXvRPCrYaAQQQQAABBBBAYGAJSOVzUpsmVZnkz3ZAzRwEEEAAAQQGlgDJ38DaX/QWAQQQ6KEAyZ/UwNh546ysLJ1Op9fr1Waxd3/Ul+pESkrKqFGjKioq1Dlms/mHH34ICQm5deuWdqbZbLZK/g4dOlRcXPzHH3/U1tZatXT0kuSvurpapKfV1dVms3nu3Lk6nW7z5s2OxJiPAAIIIIAAAggggID3CEjlc1LdlqpM8tfDUTeLIYAAAggg4DUCJH9esyvoCAIIINCXAiR/UgPjbhtPmjQpIiJCbbZ06dLOzk71pXZi79692vDvwIED2pfaltrkr6KiogcxXg8W0XbAO6dv377d6eDnzp07Vn0+efKkSP7EpZavvPKKTqdbvny5VTNeIoAAAggggAACCCDghQJS+ZxU/6Uqk/z15dCc2ggggAACCHhCgOTPE8qsAwEEEOh3AZI/qYFxt43FM/nKysrMZnNJSYntY/+0Ff7973+LtG///v1BQUHXrl3TvqtOq8nfggULgoODdTqd7K07fTL5i4iIEGGe7X+jo6NVPTERFxdnm/y99NJLVs14iQACCCCAAAIIIICAFwpI5XNS/ZeqTPLX7+N3OoAAAggggEAvBUj+egnI4ggggMDAECD5kxoYd9u4o6MjICBg3bp1ZrN5zZo1169fd77Inj17nnjiiREjRoiw0G5jNfkrLCy8ffv2nDlzXEn+bPMwdU5iYqLdFfnwzOzsbNvkb+XKlT68yWwaAggggAACCCCAgM8ISOVzUlstVZnkb2AM8uklAggggAACjgVI/hzb8A4CCCDgQwIkf1IDY1car1u3bsiQIUajMTIystv2+/fvHzJkyMiRI62e+addUJv8mc3mo0ePiuSvoqJCURRtS+20ovkZN27c+fPn1RldXV3allbTakBod8KqsXhpt6WLM+0WdPvMqqoq0R/xnL958+bxnD+3I1MQAQQQQAABBBBAoI8EpPI5qT5IVSb586EzAWwKAggggICfCpD8+emOZ7MRQMDfBEj+pAbGrjSuqqp6+OGHZ8+enZGR4bz9gQMHgoKCysvL1dt+2m1vlfwpiiKeHbhw4ULbB9rZrSB1t880pz926ztdops37RZ0ZabU3T7NZvMzzzyj+3/27vwtiivv//+/kM/9nftzf+a+M/ekXKIGFBWMAi5DNKhxX3DDDTQTFfeouLRLqwRc4jISE5fgFhFUEBQ1KC4YN3BXFHFHZGn27cw4k8zwvUg5Zaebxi7obnp5cuWaOX361KlTj/KX93ldVS1JDx8+rKmpCQgIkCTp7t275pyIMQgggAACCCCAAAIINK2AqnxO1VJVzUzy52rbBVwvAggggIDzCZD8Od895YoQQACBOgRI/lQVxmYODg4O7tGjx7/+9a96xiuxnzwmKipK/s0/40Pk3w6UJOnatWvytz///PP69esHDhxoPLjOHlXJX50z2GHn69evlacYDRpyMmqw5pSUlObNm8tvOv34448nT55sMICPCCCAAAIIIIAAAgjYp4CqfE7VJaiameSvjoqaLgQQQAABBBxKgOTPoW4Xi0UAAQQaKkDyp6owNnPwhQsXtm/fXs/glJQU+Wk//TG7du3y9fX961//qt957NixTz75RH5T5eDBg9etW7d48WI/Pz9JkhYuXKg/sp62UyZ/9Vyvqa+SkpLmzJmzfv36hQsX1pkOmjqQfgQQQAABBBBAAAEEmlBAVT6nap2qZib5a2jZzXEIIIAAAgjYiwDJn73cCdaBAAIIWFWA5E9VYWypwa9fv5Z/cM5gwsePHxv0WOTj48ePbR90nT9/fuvWrbNmzUpJSbHIVTAJAggggAACCCCAAAKuKaAqn1NFpGpmkj+r1uZMjgACCCCAgA0ESP5sgMwpEEAAgaYXIPlTVRgzWK2AEOKTTz559eqVcmD9L0FVhtFAAAEEEEAAAQQQQAABWUBVPqcKTdXMJH9NX8CzAgQQQAABBBonQPLXOD+ORgABBBxEgORPVWHM4AYIhIWFbd26VT6wurr6yJEjDZiEQxBAAAEEEEAAAQQQcFkBVfmcKiVVM5P8OUiVzzIRQAABBBAwKUDyZ5KGLxBAAAFnEiD5U1UYM7gBAjt37gwNDa2pqbl161ZAQEBaWloDJuEQBBBAAAEEEEAAAQRcVkBVPqdKSdXMJH/OtBXAtSCAAAIIuKYAyZ9r3neuGgEEXE6A5E9VYexqg1+/fr1+/fq1a9cuWLDg7t275l9+aWlpaGioRqNZtmxZcHDwlClT0tPTx44d26ZNm4ULFxYVFZk/FSMRQAABBBBAAAEEEHBxAVX5nCorVTOT/LncfgEXjAACCCDgdAIkf053S7kgBBBAoC4Bkj9VhbFLDX79+vWQIUOOHTtWU1MTGBj4zTffmHn5xcXFXbt23bt3b01NTUVFRYsWLTQaTU1NzebNm8eOHWvmJAxDAAEEEEAAAQQQQAABWUBVPqcKTdXMJH91ldT0IYAAAggg4EgCJH+OdLdYKwIIINBgAZI/VYWxSw3euHFjYGCgfMnZ2dk///yzmZcfGho6ZMgQebAQolmzZjt27KipqRk1alRkZKSZkzAMAQQQQAABBBBAAAEEZAFV+ZwqNFUzk/w1uO7mQAQQQAABBOxEgOTPTm4Ey0AAAQSsK0Dyp6owdqnBnTt3jo6ObsAlt2vX7sCBA/KBly5dkiQpOzv7b3/7W6tWrdLT0xswIYcggAACCCCAAAIIIODKAqryOVVQqmYm+bNucc7sCCCAAAIIWF+A5M/6xpwBAQQQsAMBkj9VhbHrDC4tLZUk6dy5c2ovuaioSJKk69evywcGBwePHj26pqbm4sWLrVu3/vvf/652QsYjgAACCCCAAAIIIODiAqryOVVWqmYm+bODCp4lIIAAAggg0CgBkr9G8XEwAggg4CgCJH+qCmPXGfzzzz+3b99++fLlP//8c0VFRUJCwuvXr825/F9++aVDhw7Xrl2rqam5fv26j49PQUFBTU3Nhg0bBg0adPLkyV9++cWceRiDAAIIIIAAAggggAACsoCqfE4VmqqZSf4cpcxnnQgggAACCJgSIPkzJUM/Aggg4FQCJH+qCmOXGvzjjz/6+vp+9tlnWq22oqLC/Gs/efLk1KlTN23aNGvWrMePH8sHbt68uXfv3o8ePTJ/HkYigAACCCCAAAIIIIBATU2NqnxOlZiqmUn+nGovgItBAAEEEHBJAZI/l7ztXDQCCLieAMmfqsKYwQgggAACCCCAAAIIIICAjQVU5XOq1qZqZpI/19sw4IoRQAABBJxNgOTP2e4o14MAAgjUKUDyp6owZjACCCCAAAIIIIAAAgggYGMBVfmcqrWpmpnkr86amk4EEEAAAQQcSIDkz4FuFktFAAEEGi5A8qeqMGYwAggggAACCCCAAAIIIGBjAVX5nKq1qZqZ5K/hhTdHIoAAAgggYB8CJH/2cR9YBQIIIGBlAZI/VYUxgxFAAAEEEEAAAQQQQAABGwuoyudUrU3VzCR/Vq7OmR4BBBBAAAGrC5D8WZ2YEyCAAAL2IEDyp6owZjACCCCAAAIIIIAAAgggYGMBVfmcqrWpmpnkzx5KeNaAAAIIIIBAYwRI/hqjx7EIIICAwwiQ/KkqjBlsKYFffvnFUlMxDwIIIIAAAggggAACzi2gKp9TRaFqZpI/h6nzWSgCCCCAAAImBEj+TMDQjQACCDiXAMmfqsKYwZYS0Ol027Zt+8c//mGpCZkHAQQQQAABBBBAAAFnFVCVz6lCUDUzyZ9zbQZwNQgggAACrihA8ueKd51rRgABFxQg+VNVGDO4MQKDBg3q9e+/Tz75pFWrVrNmzWrMhByLAAIIIIAAAggggIArCKjK51SBqJqZ5M8Fdwy4ZAQQQAABJxMg+XOyG8rlIIAAAnULkPypKowZbCmBv/71r0uXLi0pKbHUhMyDAAIIIIAAAggggICzCqjK51QhqJqZ5K/uoppeBBBAAAEEHEeA5M9x7hUrRQABBBohQPKnqjBmsKUESktLf/75Z0vNxjwIIIAAAggggAACCDixgKp8TpWDqplJ/hpReXMoAggggAACdiFA8mcXt4FFIIAAAtYWIPlTVRgzGAEEEEAAAQQQQAABBBCwsYCqfE7V2lTNTPJn7fKc+RFAAAEEELC2AMmftYWZHwEEELALAZI/VYWxCw4eMGBAs2bNpk+fPvO3f717905MTHQskLi4uA0bNmzdunX58uV/+9vfHGvxrBYBBBBAAAEEEEDAZQVU5XOqlFTNTPJnFzU8i0AAAQQQQKARAiR/jcDjUAQQQMBxBEj+VBXGLjj40KFDkiSlpqYaXPukSZP+/ve/G3Sa+njjxo0xY8ZIv/75+flFRET069cvODj4ypUrpg6xeH9SUlLfvn3lV4zu2LEjODjY4qdgQgQQQAABBBBAAAEErCGgKp9TtQBVM5P8OU6hz0oRQAABBBCoW4Dkr24XehGxWvJaAAAgAElEQVRAAAEnEyD5U1UYu+Dg169fe3l5ffHFF/rXfu/evXXr1un3vLP94MEDOfn7/vvva2pqTp06JUlSq1at7t+//85jLTKgd+/ekZGR8lRFRUWSJN27d88iMzMJAggggAACCCCAAAJWFVCVz6laiaqZSf6cbDeAy0EAAQQQcEEBkj8XvOlcMgIIuKIAyZ+qwtg1B69bt65Fixb5+fnK5S9ZsuTVq1fKR3Ma+fn5cvK3d+/empqaV69eyR+3bdtmzuGNHPPkyRODJxe7du0aERHRyGk5HAEEEEAAAQQQQAABGwioyudUrUfVzCR/rrhlwDUjgAACCDiXAMmfc91PrgYBBBAwIUDyp6owds3BeXl5LVu23LRpk3z5FRUVM2fOVEthkPxlZGTIyV9KSoraqeTx//jHP16b+JNf6ak/bWpqqiRJd+/eVToHDBgwffp05SMNBBBAAAEEEEAAAQTsVkDO58z8X1VXQfJnolCmGwEEEEAAAecUIPlzzvvKVSGAAAIGAiR/qgpjlx0cEhLi7e0tJ2q7du0y/tm/d8ooyd/WrVszMjLGjh3bpUuX7du3v/NAUwNGjx4tZ4fG/6vRaAyOSkxMlCTp6dOnSv+oX/+UjzQQQAABBBBAAAEEELBbATMzP3mYqqsg+TMokPmIAAIIIICAcwuQ/Dn3/eXqEEAAgTcCJH+qCmOXHZyeni5JUnJyck1NzeTJk//1r3+Zopg5c+af//xn42+V5C8kJGTt2rU+Pj6DBg06cOBAPVMZT9LgHvmZv4yMDGWGgQMHGvx4ofIVDQQQQAABBBBAAAEE7EqA5I8CHgEEEEAAAQQsIkDyZxFGJkEAAQTsXYDkz65KenteTL9+/SZMmHDlypWdO3fWs84VK1YsWrTIeICS/Mm/81dYWOju7i5J0po1a4wHW7zn2bNnkiRdvHhRmblHjx4rV65UPtJAAAEEEEAAAQQQQMBuBUj+7L2uZn0IIIAAAgg4iADJn4PcKJaJAAIINE6A5M9uy3t7W9jBgwebNWsWGBhYVlbWgLUZJH81NTWBgYGSJLVt2/af//xnAyZU9bbPmpoaf3//7777Tj5RWVlZs2bN0tLSGnBeDkEAAQQQQAABBBBAwMYCJH+Nq3o5GgEEEEAAAQTeCJD88U8BAQQQcAkBkj8bF+2Oe7rXr1937Nhx/vz5DbsEU8lfhw4dGvbCz9evXwsTf69fvzZeZFJS0oABA3755Zeampo9e/aMHj26Yec1npkeBBBAAAEEEEAAAQSsKkDy5xLFOReJAAIIIICA9QVI/qxvzBkQQAABOxAg+bNqie5kk69du/bOnTsNu6isrCzp17+tW7fW1NSUl5e3a9dOkqTIyMiGTdiAo2JiYjZt2hQVFbV8+fKKiooGzMAhCCCAAAIIIIAAAgjYXkA/+Rtc15/+AFXLkw9MfdefPOzKlSt379599OhRdnb2q1evCgoKdDpdUVFRcXGxcV1pB8UuS0AAAQQQQAABQwGSP0MRPiOAAAJOKWBcoRUXFxcVFel0uoKCglevXmVnZz969Oju3btXrlxRVUMyGAFF4NatW+PHj5eTPx8fn1WrVo0aNWrkyJHHjh1TxtBAAAEEEEAAAQQQQACBOgX0g72KigqD7M/g2zpnMNVJ8ueUZT4XhQACCCCAgCkBkj9TMvQjgAACTiVA8meqBqYfAQQQQAABBBBAAAEEELAHAYNsTz/8M/5K1YJJ/pyqvOdiEEAAAQQQeJcAyd+7hPgeAQQQcAoBkj9VhTGDEUAAAQQQQAABBBBAAAEbCxjHe3L4V2e/qrWR/DlFWc9FIIAAAgggYK4AyZ+5UoxDAAEEHFqA5E9VYcxgBBBAAAEEEEAAAQQQQMDGAnUmfKY6Va2N5M+hy3kWjwACCCCAgFoBkj+1YoxHAAEEHFKA5E9VYcxgBBBAAAEEEEAAAQQQQMDGAqZCvjr7Va2N5M8hy3gWjQACCCCAQEMFSP4aKsdxCCCAgEMJkPypKowZjAACCCCAAAIIIIAAAgjYWKDOhM9Up6q1kfw5VPnOYhFAAAEEEGisAMlfYwU5HgEEEHAIAZI/VYUxgxFAAAEEEEAAAQQQQAABGwuYCvnq7Fe1NpI/hyjbWSQCCCCAAAKWEiD5s5Qk8yCAAAJ2LUDyp6owZjACCCCAAAIIIIAAAgggYGOBOhM+U52q1kbyZ9flOotDAAEEEEDA0gIkf5YWZT4EEEDALgVI/lQVxgxGAAEEEEAAAQQQQAABBGwsYCrkq7Nf1dpI/uyyTGdRCCCAAAIIWEuA5M9assyLAAII2JUAyZ+qwpjBCCCAAAIIIIAAAggggIDTCJD82VV5zmIQQAABBBCwtgDJn7WFmR8BBBCwCwGSP6cp2rkQBBBAAAEEEEAAAQQQQECVAMmfXZTlLAIBBBBAAAFbCZD82Uqa8yCAAAJNKkDyp6owZjACCCCAAAIIIIAAAggg4DQCJH9NWo5zcgQQQAABBGwtQPJna3HOhwACCDSJAMmf0xTtXAgCCCCAAAIIIIAAAgggoEqA5K9JynBOigACCCCAQFMJkPw1lTznRQABBGwqQPKnqjBmMAIIIIAAAggggAACCCDgNAIkfzYtvzkZAggggAACTS1A8tfUd4DzI4AAAjYRIPlzmqKdC0EAAQQQQAABBBBAAAEEVAmQ/Nmk7OYkCCCAAAII2IsAyZ+93AnWgQACCFhVgORPVWHMYAQQQAABBBBAAAEEEEDAaQRI/qxabjM5AggggAAC9iZA8mdvd4T1IIAAAlYRIPlzmqKdC0EAAQQQQAABBBBAAAEEVAmQ/FmlzGZSBBBAAAEE7FWA5M9e7wzrQgABBCwqQPKnqjBmMAIIIIAAAggggAACCCDgNAIkfxYtr5kMAQQQQAABexcg+bP3O8T6EEAAAYsIkPw5TdHOhSCAAAIIIIAAAggggAACqgRI/ixSVjMJAggggAACjiJA8ucod4p1IoAAAo0SIPlTVRjX1NS84A8BBBBAAAEEEEAAAQQQsFcBVQUOyV+jymkORgABBBBAwNEESP4c7Y6xXgQQQKBBAiR/qgpjOfkT/CGAAAIIIIAAAggggAAC9ifw4sULVQUOyV+DymgOQgABBBBAwFEFSP4c9c6xbgQQQECVAMmfqsKY5M/+NjdYEQIIIIAAAggggAACCLwRIPlTVQ4zGAEEEEAAAVcTIPlztTvO9SKAgIsKkPyR/LFNggACCCCAAAIIIIAAAs4hQPLnooU9l40AAggggIB5AiR/5jkxCgEEEHBwAZI/kj/n2OPgKhBAAAEEEEAAAQQQQIDkz8ELdJaPAAIIIICAdQVI/qzry+wIIICAnQiQ/JH8sT+CAAIIIIAAAggggAACziFA8mcnhTbLQAABBBBAwD4FSP7s876wKgQQQMDCAiR/JH/OscfBVSCAAAIIIIAAAggggADJn4ULZqZDAAEEEEDAuQRI/pzrfnI1CCCAgAkBkj+SP/ZHEEAAAQQQQAABBBBAwDkESP5MFL50I4AAAggggECtAMkf/w4QQAABlxAg+bNU8ldYpssrznWO/QKuAgEEEEAAAQQQQAABBBxRgOTPJcp4LhIBBBBAAIGGCpD8NVSO4xBAAAGHEnCa5C8vL+/o0aPJycm5ubnvDPOysrJOnTqVkJBQXV39zsEGA168eFHnFsCYrYM8NJJrhn89evTw9vaWJEmn09WJY07njh07fH193d3dly1bZjy+qKhIkqRnz54pX61evXrGjBnKR9s0Io/ecw858v6E2Hk7r9rmjBY8i0VukwXXw1QIIIAAAggggAACFhcg+XOocpzFIoAAAgggYGsBkj9bi3M+BBBAoEkEnCn5O336tEFKJ3/Mzs5OSEh48uSJ/rf//Oc/HT35u5L1k4dGWhQ72+L7BfKEw4YN27t3r5mTP3v2TFXyFxERUWduN2/evDqTv4qKih07dhQXFyvraZLkTz771G8ump/8JV9/0WZKnLLspm2Yuk2mbkfTrpazI4AAAggggAACCKgVIPlrkrKakyKAAAIIIOAoAiR/jnKnWCcCCCDQKAGnT/5ev3599uzZ5ORkayd/amvyxo93qeTPmIvkz9jknT0kf+8kYgACCCCAAAIIIODQAiR/jSqPORgBBBBAAAFnFyD5c/Y7zPUhgAACvwo4ffKXlpaWm5t75swZM5O/jIyM8+fP6z8daNA2ftvn8rhQD40k/6e87XPSztETtgX0Xd8t8NvBYYlLfVa2XZe0Wghx6s4JD400c+/k8duG+6xsG7InqKAkX95cOHQ1etDGnl1Wuo36ZsCFB2eVHQe/cK8uK92+Ob2hx1eeXstbfXN6Q3FZkXJGpaErNfmmzWXLlo0YMaJz586ff/75/PnzO3ToEBUVJYTIy8sLCgry9PRs167dkCFDLl++LJ90yZIlPXr0aN26taenZ49f/0pKSoQQWq129OjREyZMGDhw4PDhwx88eKAsss5IKS8vLyQkxNPTs0uXLitWrCgrKxNCxMbG9ujRw8PDw93dXZ78/Pnzyjx1PvM3YsSI7t27G7/tMzg4eNy4ce7u7oMGDbp9+7YySZ2N7qHH/7zlpz5Lk33mJQVtTNWVVAohtp247/3lMWX8D2eyPGYkCCESLz9t9UVcyNZLvZac9Jl37Milp8oYIYTxM39V1dXa/dfdpsZLkw6NjDj7LLeWK+OZrv2MhNZfxP1/o6Pbz0hoPyNh7aF3LHLxwTn+a328lrfqutpjXnSIck83/7j20zXeXstbfRLeaXWCRn8xxm1Vt6n+22E8OT0IIIAAAggggAAC9ixA8kehjwACCCCAAAL1CJD81YPDVwgggIDzCDh38vfq1avLly/X1NSYn/xdv3792LFjBmmf/kfj5O/ak6vx6bH9vu6h/zt/k3aO9lnZdv3xMA+N9Pn3gUHbR3TWfqQkf57LP9x1ftuSQ196aKQV8QuFECduHfXQSEM2+286GeEX7uW5/MMHLzPkPQW/cC8PjTRw4ye7U7fvOr/th5+iKqsq49NjN51c46GRJmwLiE+PjU+PraiqMLUHsWzZsqlTpxYVFbm5ue3du/fs2bM9e/YUQmRnZ+/YsSM3N7eqqmrHjh1t27bVf52m8ds+tVptq1atMjMzhRA7duzo3bu3csY6k7+pU6dOnDixqKjoxYsX/v7+GzZsUMaber1kncmfEKLO3/lr3rx5SkpKRUXFV1995efnV1VVpcxv3Ogeetz7y2PFZbWB39j157/cUftDfbqSyt+Pi0nPzJPHD151Oizmppz8vTdy/74zWUKIaw/z/3t8jBzmycOMk79vkzLahhzJfFFYUl4ZvDG1/4pTygJUve2z7/pua4+tPJx2YMGBGR4aaV3SKiHE2Xun5LT4xM3EXee3yf9glPmNG2pvkxDC1O0wnpweBBBAAAEEEEAAAXsWIPlznlqdK0EAAQQQQMAKAiR/VkBlSgQQQMD+BJw4+fvHP/6RnJxcXV2tKvnTD/nqbBsnf3LlP2brIIPkb0Rkv9yiHA+NtDt1+85zWz00UlFZofzM34y9k4QQ5ZVlnbUf+a/1EUL8OWqsh0bKzLlfGztdj/PQSBFHtfLMcvL3LP+JwRaD+W/7XLZsWUREhBCiR48eP/300+PHj9u1a2cwW1VVVYsWLW7erM295L86k7/AwED525KSEkmSlMf+jJO/qqqqli1b/vTTT/L4Xbt26SeFpqImVcnf8OHD5cmLioqaNWumv3i5X/9/u4ceX3PoltyTdPX5h38+LLcnbbog/2jfi/zS/xxz4FFO7U8JJl5++vtxMdXVbybwW3Ri24naWyP/GSd/fZclfxX7hu7uU917I/fnFZXLg1Ulf0VlhfI/jCe5jzw0UvCOUUKIk7eOeWikcd8NO3HrqPKE6L/XUsf/a7Va82+TfLyp21HH7HQhgAACCCCAAAII2LEAyZ/91dysCAEEEEAAATsSIPmzo5vBUhBAAAHrCThx8nfjxo2srCw5vTP/mb860z79TvOTv5GR/fOKcz000p4LO6LOf+ehkfJL8uTkTxu/SN4u8F/r02lFKyHEoI09PTRSVXXtU2t3nt/y0Ehz90+Rx/iFe3XWtjHeXlCV/K1bt04I4efnd+XKlWfPnrm7uwshysrKtFptz549fX/9a9as2dWrtU/CyX91Jn/Tp0//9/eiTZs2qamp8kfj5O/ly5eSJGVl1T42J4RISkrq2LGj3K7nITNVyd+UKW+IhBDu7u6nT59W5jdudA89vv3f6d2ljFf/MSpaHpNyM7v55EOVVdUbj9wdoH3zrJ78tk9lkqGrU1YduKF8NE7+PGclRiXXPgophCgoqXhv5P5bjwvkj+Ynf/kleXN+mOKzsq3yBtfAbwcLIaqqq1YeWey90t1DI3kua7kqYYk8s6n/1Wq15t8meRKSP1OY9COAAAIIIIAAAo4lQPJnvdqZmRFAAAEEEHACAZI/J7iJXAICCCDwbgEnTv5Onz6d8Nu/K1euKBneP//5z4SEBPmJQKXTnEZjkr+84lw5+QvaMbL2VZOlOq/lrYyf+Tt6Pd7gmb8uK92MdxzSHl320EgLY2YZf2XQs2zZMoPkz82tdsL169cPHjw4Jyen9jmz8vIWLVpcuXJFOTYgIGDv3r3KR/l3/gICAuSe/Px8SZLu33/zJFxOTo4kSXl5b16bWZtX1fvM35o1a/TTKeUsixYtWrKkjmSrzrd9Gjzzd+vWm0f6lNn0G91Dj2v3X5d7Dl943PLzN8/8CSE8ZiQkXH7qMy9p/9lH8oDEy0//b+CB0vI3rw/1/vLYd8ffPvM367vLc7e/hRJC1PPM3+kb2a2/iNNfial2xFGth0aatjvo7L1T8ttfx2wdpAyuqKpIf3xl9NaBHhrpzvP6rlSr1Zp/m+T5Td0O5ew0EEAAAQQQQAABBBxCgOTv3TUwIxBAAAEEEHBhAZI/F775XDoCCLiSgBMnf/oxnvnP/GVkZJw7d07/WIO2QfJXWlF66Gr0oavRn33dXX6879DV6Ic5DybtHG38zJ+S/HVY2nzJwbnjtw330EjL40KFEMdvJnhopKGbe286uaZnxMeey1pmZN+VNxf8wr3qTP6eFzz10Ej+a332X9x96Gp0ReWb10sab0mYSv6WLl2qxG/ffvutJEn6yV9ISMiiRW+eTZTn1Gq1yk/rabVaf39//XN5enrGx8fr90yZMkX/d/6+/vpr5dvdu3f37du3vNxwzTt27OjXr19ZWZkyUm7Umfwpi/nqq6969uxZrbydU4ihQ4fOmzdPf5LuocfdpsZnvigsKKnoszR59ra30V1YzE2fecf+MDG2pLz2VwCV3/lbGX2jorI67uKT/xp74MmrEmW2yKP3ui04ruSCQohvjt3T/52/z5YnK4PvPSv8zzEHnua+PVz5yqAhJ38Rx7QvCp5FHF3hoZHk5O/Cg7MLDsyIubw36cYR+aWy8lthDQ5XPqq9TUIIU7dDmZMGAggggAACCCCAgEMIkPy5UjXPtSKAAAIIIKBagORPNRkHIIAAAo4oQPJnEOxdv3792LFjBp36Hw2Sv5zCl8q7GZVGzOW99Sd/Cw7MDNo+ostKt5A9Qfklb56Ti728b+DGT7qsdBsZ2f9cRoqys2Aq+RNCrEta3T2sQ/ulzTw0kq5Upxxi0DCV/L148WL06NH9+vULDAz89ttv3dzc9JO/Gzdu9O7du1OnTl26dCkpqQ2utFrt5MmTx4wZ4+bmNmTIkIyMDP0THTt2zNvb283NbdWqVXL/q1evpk6d2rFjx86dOy9dulQ/z9PpdIGBgV5eXl26dDl79qwyT3FxcXBwsLu7u5ubm05Xe0VHjhyRX0YqSZK3t7evr+8PP/wghFi9enVwcPD48ePd3NwGDx587949ZRIhROfOncePH6/f0z30eGhUmuesxP8NOjhhQ2pBSYXy7eOc4v8YFT3tm4tKT+Llp+7TjiyISnt/QkzHWYlxF3/zI4tFpZUjI86+PyH2f8bHyvNUVlUv23fto6nxHwQfHBF+Rj8mFELM23n1wz8fbjMlTvktQOVE+o284txpu4O8V7r7hXutTtAoyd/dF7fGfjvEd1U7z+Uf9lnfNer8d/pHGbfV3qbax09N3A7jyelBAAEEEEAAAQQQsGcBkj9HrMpZMwIIIIAAAjYTIPmzGTUnQgABBJpSwGmSP51Od/LkyZSUlLy8PP2grs72o0ePUlJSTpw4IYSoc0A9nQbJn9qyX37b51eJy9QeaA/jtVrt7Nmz7WElDVhD99Dju069+Sk+g8NLyivfnxBz7vZLpb82+Qs5onx0rIZD3ybHoma1CCCAAAIIIICAvQmQ/DVldc25EUAAAQQQsHsBkj+7v0UsEAEEELCEgNMkf/VkdZb9iuTP3nY3zFxPPcnf+rg7nece1Z+H5E9fgzYCCCCAAAIIIICAowiQ/FmiSmYOBBBAAAEEnFaA5M9pby0XhgACCOgLkPypzQVJ/hxl18NgnXUmf3lF5e9PiOk0O/Gne6/0x5P86WvQRgABBBBAAAEEEHAUAZI//WqXNgIIIIAAAggYCJD8GYDwEQEEEHBOAZI/Gyd/jrJlwDoRQAABBBBAAAEEEEDA4QRI/pyzbueqEEAAAQQQsJAAyZ+FIJkGAQQQsG8Bkj+SP4fbzmDBCCCAAAIIIIAAAgggUKcAyZ9919+sDgEEEEAAgSYWIPlr4hvA6RFAAAHbCJD8kfzVuWVAJwIIIIAAAggggAACCDicAMmfbepozoIAAggggICDCpD8OeiNY9kIIICAOgGSP0slf4VlurziXIfbGmDBCCCAAAIIIIAAAggg4DQCJH/q6mFGI4AAAggg4GICJH8udsO5XAQQcFUBkj9LJX9jtg7y0EiEf06zacKFIIAAAggggAACCCDgcAIkf65a2XPdCCCAAAIImCVA8mcWE4MQQAABRxcg+XPc5O9K1k8eGmlR7GyH249gwQgggAACCCCAAAIIIGANAZI/R6/QWT8CCCCAAAJWFSD5syovkyOAAAL2IkDyZ6nkzxp1e/1zkvzV78O3CCCAAAIIIIAAAgi4mgDJn71U2qwDAQQQQAABuxQg+bPL28KiEEAAAUsLkPw1PvlbHhfqoZHk/5S3fU7aOXrCtoC+67sFfjs4LHGpz8q265JWCyFO3TnhoZFm7p08fttwn5VtQ/YEFZTky/sRh65GD9rYs8tKt1HfDLjw4KyySeEX7tVlpds3pzf0+MrTa3mrb05vKC4rUs6oNHSlOuUQg0ZlZaUkSVu3bh0yZIiPj8+SJUvkAWfOnPHy8lIGS5J0584dIUSfPn0mTpzo6ekZHh4eEBDg5eWVlpYmhNBqtaNHj54wYcLAgQOHDx/+4MEDIcSDBw9atmz58uVLeZ6nT5+2aNHi8ePHyrTGjcUH5/iv9fFa3qrrao950SHKyjf/uPbTNd5ey1t9Et5pdYLG+ED9noiIiKCgoFmzZn366ac9e/a8ceOG/G3//v3nzJkTEBDQp0+f6dOnFxYW6h9FGwEEEEAAAQQQQAABJxYg+bN0xcx8CCCAAAIIOJUAyZ9T3U4uBgEEEDAlQPLX+OTv2pOr8emx/b7uof87f5N2jvZZ2Xb98TAPjfT594FB20d01n6kJH+eyz/cdX7bkkNfemikFfELhRAnbh310EhDNvtvOhnhF+7lufzDBy8z5C0Jv3AvD400cOMnu1O37zq/7YefoiqrKuPTYzedXOOhkSZsC4hPj41Pj62oqjC1hSEnf6GhoUKI3Nzctm3bXr58WQhRT/IXFRV1/vx5SZIyMzMjIiIWLVokJ3+tWrXKzMwUQuzYsaN3797yGYcOHfrtt9/K7b/85S+jRo0ytRK5v+/6bmuPrTycdmDBgRkeGmld0iohxNl7p+RM9MTNxF3nt8ks9cwTERHx0UcfPXz4UAgRHh4eGBgoD+7fv3/v3r1LSkqEEFOmTNFo3pEg1nMKvkIAAQQQQAABBBBAwLEESP5MVb70I4AAAggggEBpaSnJH/8MEEAAAZcQIPlrfPIn7wWM2TrIIPkbEdkvtyjHQyPtTt2+89xWD41UVFYoP/M3Y+8kIUR5ZVln7Uf+a32EEH+OGuuhkTJz7gshEq/HeWikiKNaeWY5+XuW/8Rg08H8t33Kyd/Vq1flGYYOHbpv3776k7+zZ88+e/asZcuWQogDBw5MnjxZTv6UgK2kpESSJPmxv3379vXp00eevFevXrGxsQZLNfhYVFb7HF55ZdmT3EceGil4R21SePLWMQ+NNO67YSduHVWegzQ4UP9jRETEuHHj5J6UlBRvb2+53b9//82bN8vt5OTkTp066R9FGwEEEEAAAQQQQAABJxYg+XOJMp6LRAABBBBAoKECJH8NleM4BBBAwKEESP6sl/yNjOyfV5zroZH2XNgRdf47D42UX5InJ3/a+NpH6IQQ/mt9Oq1oJYQYtLGnh0aqqq4SQtx5fstDI83dP0Ue4xfu1VnbRm7r/6/a5O/+/dpYUQgxYsSIHTt21J/8paamvnz5slWr2rXFxsYGBQXJyd/06dOVNbRp0yY1NVUIUVRU5ObmduvWrWvXrrVt21Z+3k4ZZtDIL8mb88MUn5VtlfeUBn47WAhRVV218shi75XuHhrJc1nLVQlvXklqcLjyMSIiYtq0afLH1NTUDh06yO3+/fvv2bNHbl+9erV58+bKITQQQAABBBBAAAEEEHBuAZI/hyrHWSwCCCCAAAK2FiD5s7U450MAAQSaRIDkz5bJX15xrpz8Be0YKYTQleq8lrcyfubv6PV4g2f+uqx0M96hSHt02UMjLYyZZfyVQY/8zJ9x8nfx4sX27dvLg3U6nf7v/BkkfxMnTpSTv4CAAHl8fn6+JEnKnHPmzNFqtcuWLZs/f77B2Q0+RhzVemikabuDzt47Jb/jdMzWQcqYiqqK9MdXRm8d6KGR7jy/pfQbN+pJ/tasWSOPT0xM1JZujaEAACAASURBVP8hQ+NJ6EEAAQQQQAABBBBAwJkESP6apKzmpAgggAACCDiKAMmfo9wp1okAAgg0SoDkr5HJX2lF6aGr0YeuRn/2dXf58b5DV6Mf5jyYtHO08TN/SvLXYWnzJQfnjt823EMjLY+r/fm94zcTPDTS0M29N51c0zPiY89lLTOy78p7EH7hXnUmf88LnnpoJP+1Pvsv7j50NbqistzUnoWp5O/ly5cffvhhRkbtDwpu377dnOSvefPmKSkpFRUVWq3W399fOeOFCxe8fv27dOmS0llnQ07+Io5pXxQ8izi6wkMjycnfhQdnFxyYEXN5b9KNI/KrU+V3n9Y5iRCinuTPx8cnKytLp9MFBAQsXrzY1Az0I4AAAggggAACCCDgZAIkf40qjzkYAQQQQAABZxcg+XP2O8z1IYAAAr8KkPw1MvnLKXypvLVSacRc3lt/8rfgwMyg7SO6rHQL2ROUX5InbzfEXt43cOMnXVa6jYzsfy4jRdmDMJX8CSHWJa3uHtah/dJmHhpJV6pTDjFomEr+hBDffPONr6/vmDFjoqKizEn+Jk+ePGbMGDc3tyFDhsiRoXIuPz+/P/3pT8pHU4284txpu4O8V7r7hXutTtAoyd/dF7fGfjvEd1U7z+Uf9lnfNer8d6ZmkPvrSf60Wq2fn1+7du2mTZum05lkqX9+vkUAAQQQQAABBBBAwOEESP4o9BFAAAEEEECgHgGSv3pw+AoBBBBwHgGSv0Ymf2r3AuS3fX6VuEztgfYwXqvVzp4929RKRo8evWHDBlPf2qy/f//+0dHRNjsdJ0IAAQQQQAABBBBAwH4ESP6cp1bnShBAAAEEELCCAMmfFVCZEgEEELA/AZI/kj/z9ynqSf6uXLnSqlWr58+fmz+blUaS/FkJlmkRQAABBBBAAAEE7F+A5M/+am5WhAACCCCAgB0JkPzZ0c1gKQgggID1BEj+SP7M378wlfwNHjy4c+fOu3fvNn8q640k+bOeLTMjgAACCCCAAAII2LkAyZ/1amdmRgABBBBAwAkESP6c4CZyCQgggMC7BUj+bJz82flOActDAAEEEEAAAQQQQAABxxUg+Xt3DcwIBBBAAAEEXFiA5M+Fbz6XjgACriRA8kfy57j7GqwcAQQQQAABBBBAAAEE9AVI/lypmudaEUAAAQQQUC1A8qeajAMQQAABRxQg+SP5098poI0AAggggAACCCCAAAKOK0Dy54hVOWtGAAEEEEDAZgIkfzaj5kQIIIBAUwqQ/JH8Oe6+BitHAAEEEEAAAQQQQAABfQGSv6asrjk3AggggAACdi9A8mf3t4gFIoAAApYQIPkj+dPfKaCNAAIIIIAAAggggAACjitA8meJKpk5EEAAAQQQcFoBkj+nvbVcGAIIIKAvQPJH8ue4+xqsHAEEEEAAAQQQQAABBPQFSP70q13aCCCAAAIIIGAgQPJnAMJHBBBAwDkFSP5I/vR3CmgjgAACCCCAAAIIIICA4wqQ/Dln3c5VIYAAAgggYCEBkj8LQTINAgggYN8CJH8kf467r8HKEUAAAQQQQAABBBBAQF+A5M++629WhwACCCCAQBMLkPw18Q3g9AgggIBtBEj+SP70dwpoI4AAAggggAACCCCAgOMKkPzZpo7mLAgggAACCDioAMmfg944lo0AAgioEyD5I/lz3H0NVo4AAggggAACCCCAAAL6AiR/6uphRiOAAAIIIOBiAiR/LnbDuVwEEHBVAZI/kj/9nQLaCCCAAAIIIIAAAggg4LgCJH+uWtlz3QgggAACCJglQPJnFhODEEAAAUcXIPkj+XPcfQ1WjgACCCCAAAIIIIAAAvoCJH+OXqGzfgQQQAABBKwqQPJnVV4mRwABBOxFgOSP5E9/p4A2AggggAACCCCAAAIIOK4AyZ+9VNqsAwEEEEAAAbsUIPmzy9vCohBAAAFLC5D8kfw57r4GK0cAAQQQQAABBBBAAAF9AZI/S1fMzIcAAggggIBTCZD8OdXt5GIQQAABUwIkfyR/+jsFtBFAAAEEEEAAAQQQQMBxBUj+TFW+9COAAAIIIIBAaWkpyR//DBBAAAGXECD5I/lz3H0NVo4AAggggAACCCCAAAL6AiR/LlHGc5EIIIAAAgg0VIDkr6FyHIcAAgg4lADJH8mf/k4BbQQQQAABBBBAAAEEEHBcAZI/hyrHWSwCCCCAAAK2FiD5s7U450MAAQSaRIDkj+TPcfc1WDkCCCCAAAIIIIAAAgjoC5D8NUlZzUkRQAABBBBwFAGSP0e5U6wTAQQQaJQAyR/Jn/5OAW0EEEAAAQQQQAABBBBwXAGSv0aVxxyMAAIIIICAswuQ/Dn7Heb6EEAAgV8FSP5I/hx3X4OVI4AAAggggAACCCCAgL4AyR+FPgIIIIAAAgjUI0DyVw8OXyGAAALOI0DyR/Knv1NAGwEEEEAAAQQQQAABBBxXgOTPeWp1rgQBBBBAAAErCJD8WQGVKRFAAAH7EyD5c4Xk78r9XPeQI80mHfKZl2S8i1FYWvHeyP1PXpUYf2VXPenp6b169aqsrLSrVdlmMTk5Od7e3jk5ObY5HWdBAAEEEEAAAQQQcFABkj/7q7lZEQIIIIAAAnYkQPJnRzeDpSCAAALWEyD5c4XkT9622Hcmq87kr6KyOvLovaJSe0/Uhg0bdvDgQf0tmO3nt/Ta8LHPGvd5B6cVlhXqf2V+e9+lnaN3DPj4q9af7xmjf9TZ+8mDv+nZJbzNuO+HZLy8q/+V+e2fss5P3j2q69p2ncI+1D/qUW5m8O6RXcLbDNjyp+O3E5SvTPULIcLCwhYuXKiMpIEAAggggAACCCCAgLEAyZ/1amdmRgABBBBAwAkESP6c4CZyCQgggMC7BUj+SP6M9wvssOfatWvt2rUrLS1V1nbyzlHfNW2vPLqYW/xq3PdDF8XNVr5S1ThxO/F0xsllCfP1k79s3XOfCLd9l3YWlhWGJS0dsOVPldUNSUbTn1xJvHn4h8tRBslfwHd9F8bNKizTJdw49PFXrR++eiCv2VS/ECIzM7N169YFBQWqro7BCCCAAAIIIIAAAi4lQPL37hqYEQgggAACCLiwAMmfC998Lh0BBFxJgOSvkclfUVHRJ598smfPHnlDYeHChRMmTKhnc6Gs4K/FL4XBf/WMj4iICAoKmjVr1qefftqzZ88bN27Ig7Va7ejRoydMmDBw4MDhw4c/ePAmOqpnqjqf+eu7PNljRoLB2z6Tr79o+fnh8Nhb3UOPu02N33P6oTLtkj3prb6I+9+gg56zEk+mv5D7u4ce//OWn/osTfaZlxS0MVVX8iYk+/7HB53nHn1/QkzbkCMLotLKKqrk8dXVYnPC3U6zE9+fENtp9tt5Tt/I9lt04g8TYzvPPZp09blyUiFEeHj4pEmT9Htmx3yupH3Jd5O6hLcprXibC+qPNKe99uRK/eRv98XtfTf7ygcWlOZ3CvvwYtZ5c+apc8zpjJP6yd/d7FsdVzd/nJclDx65rd+WlHVCCFP9ypzdunWLi4tTPtJAAAEEEEAAAQQQQMBAgOTPlap5rhUBBBBAAAHVAiR/qsk4AAEEEHBEAZK/RiZ/tYHN3bsdO3a8ffv2kSNHfH198/PzDcpv/Y/Ji/4a5Wf4X/WbREx/4Jt2RETERx999PBhbfYWHh4eGBgof6HValu1apWZmSmE2LFjR+/eves4+LdddSZ/Qgjj3/lLvv7ivZH795+tjaZ+vPbi/Qkxcmj347UXzSYdepZb+4uAD54X3nr85vmz7qHHvb88VlxWG/iNXX/+yx1X5TPvPv3wUsarisrqZ7klH885+lXsTbl/45G7bUOOpD3Iq64Wd57oUm5mCyFuP9H9v7ExB1MfV1VXp9zMfn9CzMPsIuUKxo8fHx4ernwUQgz+pufO1G8uZ12I+unbR3kPO65u3uB3cgohDJK/FYmh036Y8Lzg6Ybkr4rLi/ps9t13aaf+2VW1DZK/xBuHfSLcqqqrNp6KyHyVsTBu1tzYKUIIU/3KuYKDg1evXq18pIEAAggggAACCCCAgIEAyZ8jVuWsGQEEEEAAAZsJkPzZjJoTIYAAAk0pQPLX+ORPCBETE+Pn5+fp6Xn16pvQy6ACVz6+uiMen/+rwX/Kt8aNiIiIcePGyf0pKSne3t5yW6vVKilgSUmJJEnvfOxPVfL3+3Ex8okqKqvfG7n/wfPaX9E7db02kPvx2ovS8t9kld1Dj685dEsen3T1+Yd/Piy39f93ZfSNkRFn5Z4OMxO//9HwIcX536eNWvNmgBBi+FdnNiW8/XW9wYMHR0ZG6k/ov8k7+sruyDNfj94+IK/4VcfVzdOfXNEfoKptkPyFHp4x/1BIauaZTzd2fpr/eOhW/+3nt6iaUH+wQfIXk7a314aPC0rz/Td5H7+dsPrYkin7xtf+KzLRr0w1c+bMefPmKR9pIIAAAggggAACCCBgIEDy15TVNedGAAEEEEDA7gVI/uz+FrFABBBAwBICJH8WSf7Kyso6d+4cEBBgUHgbfyzJ/avuiTD4z3iY0hMRETFt2jT5Y2pqaocOHeS2VqudPn26MqxNmzapqanKxzobqpK/lp+/Te/eG7n/5qM3j/dFHr3Xa8nJ/x4f03d58r1ntXGgEKJ76PHtJ+7L7UsZr/5jVLTcTrmZPUB7qt30BPeQI38MOjhk9Wm5//8GHki5+VJuK/87eu25D4JrXyIq/9dmSpx2/3XlW1PP/MkDrPTMn3J2azzzp0xu8Myfcb/SExwcvGrVKuUjDQQQQAABBBBAAAEEDARI/ixRJTMHAggggAACTitA8ue0t5YLQwABBPQFSP4skvzNmzdv8uTJ/v7+27dvN6i9DT424G2fppI/JWjMz8+XJOn+/TfZm8EZlY8x5x91mXtU+ag06nzbp6nkTz6qsLRiwobUEeFn5I/dQ48rKd3hC4/lY0vKK38/LuaHM1nV1bWjtPuvD171Jvkz9czf9K2XlFUZNOr/nb9T945b/nf+/tJVXoO1f+dv1Pb+df7On9KvUHTr1u3w4beJrNJPAwEEEEAAAQQQQAABWYDkT7/apY0AAggggAACBgIkfwYgfEQAAQScU4Dkr/HJX0xMTNeuXXU6XUZGRrt27ep/4efLm+LRGcP/6tmnqOeZv+bNm6ekpFRUVGi1Wn9/f/1Jhg4davxayJuPCn4/LuZRTrH+SFO/81dn8pf+MC/1Tk5lVXV5ZdWkTRcmbbogT9U99Ljb1PjMF4UFJRV9libP3lb71s3cwvL/M2r/vac6IUSOrqzDzEQl+dsQf6dtyJH0zDwhRMYznfz8341HBX+YGHvs6rPKquqS8sqkq88zntUeK/9du3atXbt2paWl/+4QJ+8c7bq23bWnV/NL8iZEDVsUN1v5SgixYcOGv/zlL/o9ptqV1ZVllWURJ1ZM3j2qrLKsoqpCCJGte+4T4RZ9ZXdJeXHEieUDtvypsrr2Vwzlv5s3by5YsODOnTv/7jD5/9Wiuqyy7OSdY53CPiyrLCuvLJOHBnzXd3H8nOLyoqM34z7+qvXD3DfvPjXVL4R4+PBh69at6/8VSZPr4AsEEEAAAQQQQAAB1xAg+XPOup2rQgABBBBAwEICJH8WgmQaBBBAwL4FSP4amfzduXOnbdu2Stp34MABHx+fvLzaTMsif/Ukf5MnTx4zZoybm9uQIUMyMjL0T9e5c+fx42t/Os7gb/m+638MOvg/42MTLz8VQhxMfewecsR92pH3Ru7/aGq8e8iRqORMIUTy9Rd1Jn8pN7N95ye9PyGm2aRDI8LPPM97k8N1Dz0eGpXmOSvxf4MOTtiQWlBSG54JIb5NyvCanfjZ8uTRa8/N2X5FSf6qqqs3xt/xnJX4P+NjPWclnkx/IY8/dT2715KT/xt08IPg2leD3v/1xwXlr2p/+W/48IMHDyofhRDbz2/puaGTzxr3Lw9OLSx78+pRecCnn36qPBOpf4hx++vksI6rmyv/zTrwuTzmzP3kwd/07BLeZtz3QzJevv3FQSFEQkLCBx98cO7cOePZDHrOPTilzNxxdfNuaz3kAVm5mUG7R3QJb9N/S4/jtxOUo0z1CyHCwsJCQ0OVkTQQQAABBBBAAAEEEDAWIPmz7/qb1SGAAAIIINDEAiR/TXwDOD0CCCBgGwGSv0Ymf8bFtm16tFrt7Nm/ecrNNuet8yzdQ4/vOlUbGVr1Lz09vVevXpWVb5+9M3U6nU7XokWL+Ph4UwMa2b9q1apPP/20qqqqkfOYf3hOTo63t3dOTo75hzASAQQQQAABBBBAwAUFSP5sU0dzFgQQQAABBBxUgOTPQW8cy0YAAQTUCZD8kfw1fkPENsmf+etMSkrq169ftfwDg+YfZvbIvn37njhxwuzhDEQAAQQQQAABBBBAwEYCJH/q6mFGI4AAAggg4GICJH8udsO5XAQQcFUBkj+Sv8ZvQthb8tf4K2IGBBBAAAEEEEAAAQQcUYDkz1Ure64bAQQQQAABswRI/sxiYhACCCDg6AIkfw6a/DniNgRrRgABBBBAAAEEEEAAAasKkPw5eoXO+hFAAAEEELCqAMmfVXmZHAEEELAXAZI/kj+rbj0wOQIIIIAAAggggAACCNhMgOTPXipt1oEAAggggIBdCpD82eVtYVEIIICApQVI/kj+bLYNwYkQQAABBBBAAAEEEEDAqgIkf5aumJkPAQQQQAABpxIg+XOq28nFIIAAAqYESP5I/qy69cDkCCCAAAIIIIAAAgggYDMBkj9TlS/9CCCAAAIIIFBaWkryxz8DBBBAwCUESP5I/my2DcGJEEAAAQQQQAABBBBAwKoCJH8uUcZzkQgggAACCDRUgOSvoXIchwACCDiUAMkfyZ9Vtx6YHAEEEEAAAQQQQAABBGwmQPLnUOU4i0UAAQQQQMDWAiR/thbnfAgggECTCJD8kfzZbBuCEyGAAAIIIIAAAggggIBVBUj+mqSs5qQIIIAAAgg4igDJn6PcKdaJAAIINEqA5I/kz6pbD0yOAAIIIIAAAggggAACNhMg+WtUeczBCCCAAAIIOLsAyZ+z32GuDwEEEPhVgOSP5M9m2xCcCAEEEEAAAQQQQAABBKwqQPJHoY8AAggggAAC9QiQ/NWDw1cIIICA8wiQ/JH8WXXrgckRQAABBBBAAAEEEEDAZgIkf85Tq3MlCCCAAAIIWEGA5M8KqEyJAAII2J8AyR/Jn822ITgRAggggAACCCCAAAIIWFWA5M/+am5WhAACCCCAgB0JkPzZ0c1gKQgggID1BEj+SP6suvXA5AgggAACCCCAAAIIIGAzAZI/69XOzIwAAggggIATCJD8OcFN5BIQQACBdwuQ/JH82WwbghMhgAACCCCAAAIIIICAVQVI/t5dAzMCAQQQQAABFxYg+XPhm8+lI4CAKwmQ/JH8WXXrgckRQAABBBBAAAEEEEDAZgIkf65UzXOtCCCAAAIIqBYg+VNNxgEIIICAIwqQ/JH82WwbghMhgAACCCCAAAIIIICAVQVI/hyxKmfNCCCAAAII2EyA5M9m1JwIAQQQaEoBkj+SP6tuPTA5AggggAACCCCAAAII2EyA5K8pq2vOjQACCCCAgN0LkPzZ/S1igQgggIAlBEj+SP5stg3BiRBAAAEEEEAAAQQQQMCqAiR/lqiSmQMBBBBAAAGnFSD5c9pby4UhgAAC+gIkfyR/Vt16YHIEEEAAAQQQQAABBBCwmQDJn361SxsBBBBAAAEEDARI/gxA+IgAAgg4pwDJH8mfzbYhOBECCCCAAAIIIIAAAghYVYDkzznrdq4KAQQQQAABCwmQ/FkIkmkQQAAB+xYg+SP5s+rWA5MjgAACCCCAAAIIIICAzQRI/uy7/mZ1CCCAAAIINLEAyV8T3wBOjwACCNhGgOSP5M9m2xCcCAEEEEAAAQQQQAABBKwqQPJnmzqasyCAAAIIIOCgAiR/DnrjWDYCCCCgToDkz0rJX3p6uq+vb8eOHfv06WON2j54Y6p7yJHfjYmOu/ik8fMXFhZ27do1Kyur8VPZeIbEy0/bz0hQddKgoKDY2Nh3HpKTk+Pt7Z2Tk2Mw0lS/wTA+IoAAAggggAACCCBgewGSP3X1MKMRQAABBBBwMQGSPxe74VwuAgi4qgDJn5WSP7nIj42NrTP5i4iImDFjRuM3AtrPSDA/+Vu+73rwxtQ6TxoRETF//vw6v7LzzofZRfvOqAgsz5w54+fnV11dbc51hYWFLVy40HikqX7jkfQggAACCCCAAAIIIGBLAZI/V63suW4EEEAAAQTMEiD5M4uJQQgggICjC5D8kfyVlpZ26NAhLS3NllsSTXWuiRMnbtmyxcyzZ2Zmtm7duqCgwGC8qX6DYXxEAAEEEEAAAQQQQMDGAiR/jl6hs34EEEAAAQSsKkDyZ1VeJkcAAQTsRYDkr/HJX//+/efMmRMQENCnT5/p06cXFhYq5b3xM3+xsbE9evTw8PBwd3fv8evf+fPnlfHGjdCotP4rTg0LS/nTwhO9l/5479nbyYUQxs/85RaWT9yQ2nzyoTZT4hZEpZVVVAkh9p3Jaj8j4Y9BB9+fENt+RkL7GQkpN7OVc6WkpHh4eOg/Brdv3z4/P7+ioiIhRGZmZvv27S9duqSMN78xbNgwrVY7ZsyYHj16jBkzRo7QioqKJElavnz58OHDP/3006+//vqdE+4/+6jjrMQ/TIxtMyVufdwdefzT3JL2MxJafRFn8LZPf82PoVFpA7Sn2s9IGKA9lV9UrsxfUlLSsmXLmzdvKj23b99u3779rVu3hBBlZWV9+/aNjIxUvhVCdOvWLS4uTr9HbpvqNx5JDwIIIIAAAggggAACNhMg+bOXSpt1IIAAAgggYJcCJH92eVtYFAIIIGBpAZI/iyR/vXv3LikpEUJMmTJFo9Eohb1x8id/Zf7bPkOj0v5r7IH7z2sDv8ij93zmHVMmrzP5G//1+eFfnSksrXyWW9Jl7tGwmLcpl6m3fW7ZsmXo0KH60wohZs+ePXPmzLKysn79+m3dutXgWzM/Dhs27LPPPisuLq6qqgoICNi8ebMQQk7+5s2bJ4TQ6XTdu3dPTEysZ8Lissr/HHPgZPoLIUReUfm52y/1Bxv/zp+/5seuC5KKSiurqqv7Lktec6g21ZP/0tLSJEmqqKj4d0ft/0dHR/v5+RUXFy9evDgoKEj/KyFEcHDw6tWrDTrr6TceSQ8CCCCAAAIIIIAAAjYTIPmzdMXMfAgggAACCDiVAMmfU91OLgYBBBAwJUDyZ5HkT860hBDJycmdOnVSCnuLJH+DVp6WJywuq3xv5H79x/4Mnvmrqq7+3ZhoJRv77vh97y/fJoWmkr+wsLDx48cra5YbJSUl/v7+AwcOnDx5ssFX5n8cNmyY8mrN8PDwmTNnKsnf5cuX5XlWrVoVEhJSz5xFpZX/b2zMXxLv6j+9p4yvM/lbd/i2PGDZvmuTNl1QBp86dapNmzbKR6Xx5ZdfDhw4sFu3bsYv9pw5c6YcUiqD5YapfoNhfEQAAQQQQAABBBBAwJYCJH+mKl/6EUAAAQQQQKC0tJTkj38GCCCAgEsIkPxZJPnbs2ePXM9fvXq1efPmSm1vkeQvaGOqMuHvx8Xov6jTIPl7kV/63sj9mS/evBE0/uKTZpMOKceaSv7qfOZPCLF9+3ZJkup/GakyeZ2NYcOG7dq1S/5q3bp1X3zxhZL83b9/X+6PjIwcMWJEnYcrnT9eezEsLOUPE2M7zz165NJTpV8IUWfy993xN5OvjL4RuO6cMr7OZ/6EELdu3ZIkae3atcpIpREcHLxq1Srlo9Iw1a8MoIEAAggggAACCCCAgO0FSP5cooznIhFAAAEEEGioAMlfQ+U4DgEEEHAoAZI/iyR/a9askav6xMRELy8vpcKPj4/39/dXPiqNNWvWTJ8+XflYTyM0Kq3P0mR5QF5R+Xsj9999qlPGd5qdeOjCY+Vj/c/8afdf1w8RlaNSUlLatWun/zt/QogHDx506NBh1apV3bt31+nenlE5ypxGPcnfuXNvAjmNRjNt2jRzZquqrt505M4fJsbqD1aV/Bn/zp8QorS0tHfv3itWrGjfvn16err+5PLv/B0+fNigs55+45H0IIAAAggggAACCCBgMwGSP4cqx1ksAggggAACthYg+bO1OOdDAAEEmkSA5M8iyZ+Pj09WVpZOpwsICFi8eLFS2N+5c6dNmzZPnjxReuTG7t27+/btW15ebtAfHx/frVu327ffvKxSCBEalfYfo6JPpr+oqKwOjUrrMveo/iGB687N2X5Fv2fs+t/8zt/qA29/52/bifu+85PKK6v0x8vRV4cOHdLS0pR++VWf27ZtE0LMnTt30qRJyldCiPj4+AULFhj8Wp7+AKVdT/I3bty4oqKiBw8eeHp6xsfHK4cYC+QWlsf99KS4rFIIsTUp46OpbwerfeZPCDFx4kTlBaTySefOnSu/0TQmJsbX1zc/P19ZzMOHD1u3bq3fI39lql85kAYCCCCAAAIIIIAAAk0iQPLXJGU1J0UAAQQQQMBRBEj+HOVOsU4EEECgUQIkfxZJ/rRarZ+fX7t27aZNm2bwhFxERISHh4ebm9uJEyeU4l+n0wUGBnp5eXXp0uXs2bNK/549ez744AP9EC40Km3UmrMDV576n/GxvZacvPPkN4/f3X2q67og6b/Hx/RaclKeJEdXNv7r880mHWr9Rdy8nVdLy9/mfAUlFYNWnm7x+eE2U+JOXc9WTiqEWLNmzfz585WemTNnBgUFyR9LSkp69eoVGRmpfLt48eKWLVsax5bKAKVRT/K3adMmr1//DN6xaSyQoyvruyz5f4MO/jHooN+iE+fv5Mjzh0aluYccafH54d+NiXYPOeIecuT2rzj+mh9Nve1TCHH27Fk/Pz/lAccffvjB19dX+Xm/OXPmTJw4UVl/WFhYaGio8lFpmOpXBtBAtcbdQAAAIABJREFUAAEEEEAAAQQQQKBJBEj+GlUeczACCCCAAALOLkDy5+x3mOtDAAEEfhUg+bNI8hcdHW2lwj40Ku3zv/xkpcmVaQsLC7t165aVlaX01NMYMGDAwoUL6xlQ/1dFRUWSJD1+/PYlpfWPt/i3wcHBsbG/eWVonafIycnx9vbOyXkTNCpjTPUrA2gggAACCCCAAAIIINBUAiR/FPoIIIAAAgggUI8AyV89OHyFAAIIOI8AyR/Jn6pdiYKCAnd39+zs3zwyqGqGJk/+VK2WwQgggAACCCCAAAIIOJAAyZ/z1OpcCQIIIIAAAlYQIPmzAipTIoAAAvYnQPJH8mfjjQySPxuDczoEEEAAAQQQQAAB1xEg+bO/mpsVIYAAAgggYEcCJH92dDNYCgIIIGA9AZK/xid/rrOPwJUigAACCCCAAAIIIICAPQuQ/FmvdmZmBBBAAAEEnECA5M8JbiKXgAACCLxbgOSP5M+edy5YGwIIIIAAAggggAACCJgvQPL37hqYEQgggAACCLiwAMmfC998Lh0BBFxJgOSP5M/8fQRGIoAAAggggAACCCCAgD0LkPy5UjXPtSKAAAIIIKBagORPNRkHIIAAAo4oQPJH8mfPOxesDQEEEEAAAQQQQAABBMwXIPlzxKqcNSOAAAIIIGAzAZI/m1FzIgQQQKApBUj+rJT8paen+/r6duzYsU+fPuYX6uaPDN6Y6h5y5HdjouMuPjH/KFMjCwsLu3btmpWVZWqAM/UHBQXFxsa+84pycnK8vb1zcnIMRprqNxjGRwQQQAABBBBAAAEEbC9A8teU1TXnRgABBBBAwO4FSP7s/haxQAQQQMASAiR/Vkr+5CI/Nja2zuQvIiJixowZjd8IaD8jwfzkb/m+68EbU+s8aURExPz58+v8ysk6z5w54+fnV11dbc51hYWFLVy40HikqX7jkfQggAACCCCAAAIIIGBLAZI/S1TJzIEAAggggIDTCpD8Oe2t5cIQQAABfQGSP5K/0tLSDh06pKWl2XJLoqnONXHixC1btph59szMzNatWxcUFBiMN9VvMIyPCCCAAAIIIIAAAgjYWIDkT7/apY0AAggggAACBgIkfwYgfEQAAQScU4Dkr/HJX//+/efMmRMQENCnT5/p06cXFhYq5b3xM3+xsbE9evTw8PBwd3fv8evf+fPnlfHGjdCotP4rTg0LS/nTwhO9l/5479nbyYUQxs/85RaWT9yQ2nzyoTZT4hZEpZVVVAkh9p3Jaj8j4Y9BB9+fENt+RkL7GQkpN7OVc6WkpHh4eOg/Brdv3z4/P7+ioiIhRGZmZvv27S9duqSMN78xbNgwrVY7ZsyYHj16jBkzRo7QioqKJElavnz58OHDP/3006+//vqdExaUVMzZfsU95MgfJsT2WZr8KKdYCFFVXa3df91tarw06dDIiLPPckvkefKLykevPdds0qE/Bh38ZNGJp//uF0KUlJS0bNny5s2byhlv377dvn37W7duCSHKysr69u0bGRmpfCuE6NatW1xcnH6P3DbVbzySHgQQQAABBBBAAAEEbCZA8uecdTtXhQACCCCAgIUESP4sBMk0CCCAgH0LkPxZJPnr3bt3SUlt8jRlyhSNRqMU9sbJn/yV+W/7DI1K+6+xB+4/rw38Io/e85l3TJm8zuRv/Nfnh391prC08lluSZe5R8Ni3qZcpt72uWXLlqFDh+pPK4SYPXv2zJkzy8rK+vXrt3XrVoNvzfw4bNiwzz77rLi4uKqqKiAgYPPmzUIIOfmbN2+eEEKn03Xv3j0xMbH+CUeEnxm86vTzvNLKqupT17NljW+TMtqGHMl8UVhSXhm8MbX/ilPyJMv2Xeu/4lRJeWVVdfVP917lFpYrk6elpUmSVFFRofQIIaKjo/38/IqLixcvXhwUFKT/lRAiODh49erVBp319BuPpAcBBBBAAAEEEEAAAZsJkPzZd/3N6hBAAAEEEGhiAZK/Jr4BnB4BBBCwjQDJn0WSPznTEkIkJyd36tRJKewtkvwNWnlanrC4rPK9kfv1H/szeOavqrr6d2Oiz91+KY//7vh97y/fJoWmkr+wsLDx48cra5YbJSUl/v7+AwcOnDx5ssFX5n8cNmyY8mrN8PDwmTNnKsnf5cuX5XlWrVoVEhJSz5xPc0veG7n/wa/Zp/6wvsuSv4p9k2vefap7b+T+vKLakG/FD9e7LTh+7WG+8W/5nTp1qk2bNvqTyO0vv/xy4MCB3bp1M36x58yZM+WQ0uAoU/0Gw/iIAAIIIIAAAggggIAtBUj+bFNHcxYEEEAAAQQcVIDkz0FvHMtGAAEE1AmQ/Fkk+duzZ49cz1+9erV58+ZKbW+R5C9oY6oy4e/Hxei/qNMg+XuRX/reyP2ZL968ETT+4pNmkw4px5pK/up85k8IsX37dkmS6n8ZqTJ5nY1hw4bt2rVL/mrdunVffPGFkvzdv39f7o+MjBwxYkSdh8udqXdy/s+o/cYxnuesxKjkTHlMQUnFeyP333pc+4N8haWVi3aldZqd+P6EmEmbLhSWvn3Cr85n/oQQt27dkiRp7dq1xssIDg5etWqV+f3GI+lBAAEEEEAAAQQQQMBmAiR/6uphRiOAAAIIIOBiAiR/LnbDuVwEEHBVAZI/iyR/a9askYv5xMRELy8vpbCPj4/39/dXPiqNNWvWTJ8+XflYTyM0Kq3P0mR5QF5R+Xsj9999qlPGd5qdeOjCY+Vj/c/8afdf1w8RlaNSUlLatWun/zt/QogHDx506NBh1apV3bt31+nenlE5ypxGPcnfuXPn5Bk0Gs20adPqmU3tM3/KVI9zir1mJ26Mv6P0GP/OnxCitLS0d+/eK1asaN++fXp6ujJYbnTr1u3w4cMGnfLv/9XZbzySHgQQQAABBBBAAAEEbCZA8ueqlT3XjQACCCCAgFkCJH9mMTEIAQQQcHQBkj+LJH8+Pj5ZWVk6nS4gIGDx4sVKYX/nzp02bdo8efJE6ZEbu3fv7tu3b3n525+gk/vj4+O7det2+/ZtZXxoVNp/jIo+mf6iorI6NCqty9yjyldCiMB15+Zsv6LfM3b9b37nb/WBt7/zt+3Efd/5SeWVVfrj5eirQ4cOaWlpSr/8qs9t27YJIebOnTtp0iTlKyFEfHz8ggULDH4tT3+A0q4n+Rs3blxRUdGDBw88PT3j4+OVQ4wFhBDDv3r7O38pN7PlN39+c+ye/u/8fbb8TT56PO15xrPaqPKVrqzT7MTvf3ygTC6EmDhxovICUrl/7ty58htNY2JifH198/PzlfEPHz5s3bq1fo/8lal+5UAaCCCAAAIIIIAAAgg0iQDJn6NX6KwfAQQQQAABqwqQ/FmVl8kRQAABexEg+bNI8qfVav38/Nq1azdt2jSDJ+QiIiI8PDzc3NxOnDihFP86nS4wMNDLy6tLly5nz55V+vfs2fPBBx/oh3ChUWmj1pwduPLU/4yP7bXk5J0nv3n87u5TXdcFSf89PqbXkpPyJDm6svFfn2826VDrL+Lm7bxaWv425ysoqRi08nSLzw+3mRJ36nq2clIhxJo1a+bPn6/0zJw5MygoSP5YUlLSq1evyMhI5dvFixe3bNnSOLZUBiiNepK/TZs2ef36Z/COTWMBIUR+ccWs7y67TY1/f0KMv+bHrJdFQojKqupl+659NDX+g+CDI8LPPHlVIp838ug9jxkJ70+IafWrQGVVtbIeIcTZs2f9/PyUBxx/+OEHX19f5ef95syZM3HiRGV8WFhYaGio8lFpmOpXBtBAAAEEEEAAAQQQQKBJBEj+7KXSZh0IIIAAAgjYpQDJn13eFhaFAAIIWFqA5M8iyV90dLSVCvvQqLTP//KTlSZXpi0sLOzWrVtWVpbSU09jwIABCxcurGdA/V8VFRVJkvT48duXlNY/3uLfBgcHx8bGvnPanJwcb2/vnJwcg5Gm+g2G8REBBBBAAAEEEEAAAdsLkPxZumJmPgQQQAABBJxKgOTPqW4nF4MAAgiYEiD5I/lTtR9RUFDg7u6enf2bRwZVzdDkyZ+q1TIYAQQQQAABBBBAAAEHEiD5M1X50o8AAggggAACpaWlJH/8M0AAAQRcQoDkj+TPxhsZJH82Bud0CCCAAAIIIIAAAq4jQPLnEmU8F4kAAggggEBDBUj+GirHcQgggIBDCZD8NT75c519BK4UAQQQQAABBBBAAAEE7FmA5M+hynEWiwACCCCAgK0FSP5sLc75EEAAgSYRIPkj+bPnnQvWhgACCCCAAAIIIIAAAuYLkPw1SVnNSRFAAAEEEHAUAZI/R7lTrBMBBBBolADJH8mf+fsIjEQAAQQQQAABBBBAAAF7FiD5a1R5zMEIIIAAAgg4uwDJn7PfYa4PAQQQ+FWA5I/kz553LlgbAggggAACCCCAAAIImC9A8kehjwACCCCAAAL1CJD81YPDVwgggIDzCJD8kfyZv4/ASAQQQAABBBBAAAEEELBnAZI/56nVuRIEEEAAAQSsIEDyZwVUpkQAAQTsT4Dkj+TPnncuWBsCCCCAAAIIIIAAAgiYL0DyZ381NytCAAEEEEDAjgRI/uzoZrAUBBBAwHoCJH8kf+bvIzASAQQQQAABBBBAAAEE7FmA5M96tTMzI4AAAggg4AQCJH9OcBO5BAQQQODdAiR/JH/2vHPB2hBAAAEEEEAAAQQQQMB8AZK/d9fAjEAAAQQQQMCFBUj+XPjmc+kIIOBKAiR/JH/m7yMwEgEEEEAAAQQQQAABBOxZgOTPlap5rhUBBBBAAAHVAiR/qsk4AAEEEHBEAZI/kj973rlgbQgggAACCCCAAAIIIGC+AMmfI1blrBkBBBBAAAGbCZD82YyaEyGAAAJNKUDyR/Jn/j4CIxFAAAEEEEAAAQQQQMCeBUj+mrK65twIIIAAAgjYvQDJn93fIhaIAAIIWEKA5I/kz553LlgbAggggAACCCCAAAIImC9A8meJKpk5EEAAAQQQcFoBkj+nvbVcGAIIIKAvQPJH8mf+PgIjEUAAAQQQQAABBBBAwJ4FSP70q13aCCCAAAIIIGAgQPJnAMJHBBBAwDkFSP5I/ux554K1IYAAAggggAACCCCAgPkCJH/OWbdzVQgggAACCFhIgOTPQpBMgwACCNi3AMkfyZ/5+wiMRAABBBBAAAEEEEAAAXsWIPmz7/qb1SGAAAIIINDEAiR/TXwDOD0CCCBgGwGSP5I/e965YG0IIIAAAggggAACCCBgvgDJn23qaM6CAAIIIICAgwqQ/DnojWPZCCCAgDoBkj+SP/P3ERiJAAIIIIAAAggggAAC9ixA8qeuHmY0AggggAACLiZA8udiN5zLRQABVxUg+SP5s+edC9aGAAIIIIAAAggggAAC5guQ/LlqZc91I4AAAgggYJYAyZ9ZTAxCAAEEHF2A5I/kz/x9BEYigAACCCCAAAIIIICAPQuQ/Dl6hc76EUAAAQQQsKoAyZ9VeZkcAQQQsBcBkj+SP3veuWBtCCCAAAIIIIAAAgggYL4AyZ+9VNqsAwEEEEAAAbsUIPmzy9vCohBAAAFLC5D8kfyZv4/ASAQQQAABBBBAAAEEELBnAZI/S1fMzIcAAggggIBTCZD8OdXt5GIQQAABUwIkf1ZK/tLT0319fTt27NinTx9rbA0s33d9woZUS81cWFjYtWvXrKwsZcKcnBxvb++cnBylhwYCCCCAAAIIIIAAAgjYuQDJn6nKl34EEEAAAQQQKC0tJfnjnwECCCDgEgIkf1ZK/uQdgdjY2DqTv4iIiBkzZjRm18CyyV9ERMT8+fMN1hMWFrZw4UKDTj4igAACCCCAAAIIIICA3QqQ/LlEGc9FIoAAAggg0FABkr+GynEcAggg4FACJH8kf6WlpR06dEhLSzPYv8jMzGzd+v9n786jo6rz/P/PmTN/z/Rs58zp+ba20PJzXFJCAgLKKGrTuHXbdtva2morjm0L2mOPdrFKo1BhX1UIIjuIbJWVACHsIWwhbGEPEALZCdlu7ffW71RKqmOSqtRy93rW6TPeuvdzP5/353G5c84nr1P33lNTU9NpP18RQAABBBBAAAEEEEBAnwIkf4ZajlMsAggggAACaguQ/KktzngIIICAJgIkf4knf88+++yHH3744osvDh8+fNSoUXV1daG/AnT9zd+333776KOPWiyW+++//9H2z+7du0Ptu90Yt+Lw//eHTXe8uT71T1n5h68G20xcdfS303eNmLv3h6+vS/vfrMNnq4L7b9Q1/X72nt5vb/ivdzf9ZemhW82tZ6/W/fsr3zQ2tXbs/KWpO2dvPhHcs2PHDovF0tbW1rFBcHvIkCGbNm3qup89CCCAAAIIIIAAAgggoEMBkj9NltUMigACCCCAgFEESP6McqWoEwEEEEhIgORPluTvZz/72c2bNwVBePfdd8ePHx/6E0DX5C94KPqnfW49crXXiA2XbwQ6P3OlrvTid7/Am7jq6H/8bl3+4auNTa3vLNj3i08Lgj2/Pmv3r22FdY0tl2/cHPjn7CnrjgmCcM8fNu0+8b039vV5Z+P+U9eDpyxYsOCFF14I1dxx46233po8eXLHPWwjgAACCCCAAAIIIICAbgVI/hJaHnMyAggggAACZhcg+TP7FWZ+CCCAQLsAyZ8syd+8efOCi/9t27b1798/9IeAxJO/7Ucr/t8b67YeCSR8oW4FQZi46ugzf90W3JN36Mq9f9wsCEJrW9u/vbJ21/Frwf2L8soG/V+OIAivz9o9x36yqaX1rhEb8g5dOVdR/8PX1zW3fPcjvylTprz++usdOw9tf/DBBx999FHoKxsIIIAAAggggAACCCCgZwGSPxb6CCCAAAIIIBBBgOQvAg6HEEAAAfMIkPzJkvytWLEiuP4/ePBg7969Q38LSDz5EwTh8+xTT47L/+Hr656auO3U5e8eJTpx1dE3Zu8JDrTj2LW7RmwQBOFqdeMPXlpz9up3bTbvv9Srff/n2ad+N3N3QUnFY6O3/N9XB9fuPB9KDQVBiPybv88++yw0HTYQQAABBBBAAAEEEEBAzwIkf+ZZqzMTBBBAAAEEFBAg+VMAlS4RQAAB/QmQ/MmS/E2bNi24/s/KykpLSwv9LWDz5s3Dhg0LfQ1tTJs2bdSoUaGv0WzUNTa/MXvPb9ILg427Tf7C/ebv8Lmqe/+4eezyw/mHrw4ds+WjJQc/XVsSGnTHjh0pKSnh3vO3cePGUEs2EEAAAQQQQAABBBBAQM8CJH/6W3NTEQIIIIAAAjoSIPnT0cWgFAQQQEA5AZI/WZK/wYMHnz9/vra29sUXXxw7dmzobwEnTpz4r//6r0uXLoX2BDeWL1/+1FNPNTU1ddq/efPmIUOGHD9+PLT/8LmqPScqW1rbmlpaR8zdO2Lu3uChbpM/QRB+N/N77/mb/E3gPX9tbcKPfv9t///Nam5pe3POnv96d9P2oxWhIRobG/v27Xvo0KHQnuDGuXPn7rnnnurq6k77+YoAAggggAACCCCAAAL6FCD5U27tTM8IIIAAAgiYQIDkzwQXkSkggAACPQuQ/MmS/E2aNGno0KEpKSnvvfdebW1tx78CTJ061WKx3HfffVu2bAntr62tffXVV9PS0gYOHLhz587Q/hUrVvz4xz/uGMLtOFbx8Me5/++Ndb1GbPhNeuGVqsZg43DJX2Xtrddn7e41YsM9f9j00ZKDobcDvjB5xyvTdwmCsGbnhX97ZW19Y0toUEEQpk2b9vHHH3fcIwjClClTrFZrp518RQABBBBAAAEEEEAAAd0KkPz1vAamBQIIIIAAAkksQPKXxBefqSOAQDIJkPzJkvytXbtWt4v/aAqrq6sbMmTI+fPnQ40rKysHDRpUWVkZ2sMGAggggAACCCCAAAII6FyA5C+ZVvPMFQEEEEAAgZgFSP5iJuMEBBBAwIgCJH8kfzr/4wXlIYAAAggggAACCCCAQJQCJH9GXJVTMwIIIIAAAqoJkPypRs1ACCCAgJYCJH8kf1H+EYFmCCCAAAIIIIAAAgggoHMBkj8tV9eMjQACCCCAgO4FSP50f4koEAEEEJBDgOQv8eRP54t/ykMAAQQQQAABBBBAAIEkESD5k2OVTB8IIIAAAgiYVoDkz7SXlokhgAACHQVI/kj+kuSPIEwTAQQQQAABBBBAAAHTC5D8dVztso0AAggggAACnQRI/jqB8BUBBBAwpwDJH8mf6f/8wQQRQAABBBBAAAEEEEgSAZI/c67bmRUCCCCAAAIyCZD8yQRJNwgggIC+BUj+SP6S5I8gTBMBBBBAAAEEEEAAAdMLkPzpe/1NdQgggAACCGgsQPKn8QVgeAQQQEAdAZI/kj/T//mDCSKAAAIIIIAAAgggkCQCJH/qrKMZBQEEEEAAAYMKkPwZ9MJRNgIIIBCbAMkfyV+S/BGEaSKAAAIIIIAAAgggYHoBkr/Y1sO0RgABBBBAIMkESP6S7IIzXQQQSFYBkr84kr+rfBBAAAEEEEAAAQQQQAABXQrEtMBpbv/s6ekTbFZcXHzy5MkLFy5UVFRcv369pqamtra2vr6+oaGh67oyWVfYzBsBBBBAAAFdC5D86fryUBwCCCAgl0DXFVpDQ0N9fX1tbW1NTc3169crKiouXLhw8uTJ4uLimNaQNEYAAQQQQAABBBBAAAEEENCzAMmfXCtr+kEAAQQQQMAQAiR/hrhMFIkAAggkKkDyp+d1OLUhgAACCCCAAAIIIIAAAsoJkPwluqLmfAQQQAABBAwlQPJnqMtFsQgggEC8AiR/yq2i6RkBBBBAAAEEEEAAAQQQ0LMAyV+8K2nOQwABBBBAwJACJH+GvGwUjQACCMQqQPKn53U4tSGAAAIIIIAAAggggAACygmQ/MW6gqY9AggggAAChhYg+TP05aN4BBBAIFoBkj/lVtH0jAACCCCAAAIIIIAAAgjoWYDkL9qVM+0QQAABBBAwhQDJnykuI5NAAAEEehIg+dPzOpzaEEAAAQQQQAABBBBAAAHlBEj+eloxcxwBBBBAAAFTCZD8mepyMhkEEEAgnADJn3KraHpGAAEEEEAAAQQQQAABBPQsQPIXbqXMfgQQQAABBEwpQPJnysvKpBBAAIHOAiR/el6HUxsCCCCAAAIIIIAAAgggoJwAyV/nFTLfEUAAAQQQMLUAyZ+pLy+TQwABBG4LkPwpt4qmZwQQQAABBBBAAAEEEEBAzwIkf7dXxvwXAQQQQACBpBAg+UuKy8wkEUAAAZI/Pa/DqQ0BBBBAAAEEEEAAAQQQUE6A5I+/CSCAAAIIIJBUAiR/SXW5mSwCCCSvAMmfcqtoekYAAQQQQAABBBBAAAEE9CxA8pe8fwtg5ggggAACSSlA8peUl51JI4BA8gmQ/Ol5HR6htn/9139N5YMAAkkg8G//9m8R/l8BhxBAAAEEEEAAgUQESP6S728AzBgBBBBAIKkFSP6S+vIzeQQQSB4Bkr9E1skanpuamqrh6AyNAAKqCXCzq0bNQAgggAACCCShAMlf8qz9mSkCCCCAAAKNjY0kf/wzQAABBJJCgOTPoMt7wgCDXjjKRiBWAW72WMVojwACCCCAAALRC5D8JcWyn0kigAACCCBwW4Dk77YE/0UAAQRMLUDyF/2qWFctCQN0dTkoBgHlBLjZlbOlZwQQQAABBBAg+TP1cp/JIYAAAggg0FmA5K+zCN8RQAABUwqQ/Bl0tU8YYNALR9kIxCrAzR6rGO0RQAABBBBAIHoBkj9TLvOZFAIIIIAAAuEESP7CybAfAQQQMJUAyV/0q2JdtSQM0NXloBgElBPgZlfOlp4RQAABBBBAgOTPVMt7JoMAAggggEBPAiR/PQlxHAEEEDCFAMmfQVf7hAEGvXCUjUCsAtzssYrRHgEEEEAAAQSiFyD5M8WynkkggAACCCAQrQDJX7RStEMAAQQMLUDyF/2qOO6Wb7755r//+7/fd999nXqQJOn999/v3bv3Aw88UFJSEjyan5/fp0+f3r17p6end2rf8SthQEcNthEwsQA3u4kvLlNDAAEEEEBAcwGSP0Mv5ykeAQQQQACBWAVI/mIVoz0CCCBgSAGSPxUW23v27CkpKema/OXl5Q0fPlySpOLi4gEDBvj9fp/P16tXr/LycrfbnZKSUlZWFq48woBwMuxHwGQC3Owmu6BMBwEEEEAAAV0JkPwZchlP0QgggAACCMQrQPIXrxznIYAAAoYSIPlTZ+F95cqVrsnfO++8s3bt2mABffr0qaqqOnDgwLBhw4J7bO2fcOVFHwZ4L+zwFH3hPb9dvHnFL/rCdajC/msNbTnHrm0+fHX9wStZRyvqWhwqDMoQcQp43b7rxzyHvvYcWuY9k+u7dkRyC3F2JcdpN24J+87XZJdULNtzMfNIReXNNkmS5OjYAH1Ef7MbYDKUiAACCCCAAAI6EyD5M9TynWIRQAABBBBIVIDkL1FBzkcAAQQMIUDyp87Su9vk75lnntm3b1+wgMcff/zIkSMbNmwYMWJEcM/KlStHjhzZqbyMjIzU9s8dd9zR6VC4r+78CYItNfg/x+xHPPsXSM6WcI2V2N8kuJftufjygt0Wq73j/x4cnfnK57uX7j4vuL1KjEuf8Qn4Ko8617wuTBsQ+mfz3cbMwe5tk8SGy/F1G99ZPlEqLKt6Z0nRg6MzO/7jsVjtP7VttWWdaGxzx9ezgc4i+TPQxaJUBBBAAAEEDCdA8meIZTtFIoAAAgggIJcAyZ9ckvSDAAII6FqA5E+dxXm3yd/TTz/dMfk7evTo+vXrOyZ/o0aNCldeTGGA5Gz2VZZ4jn3jXPumYEt1zBrs2TfP71Mjb9tx+sZjn+VbrPYX5+38etf5C9XNlTfbqpuEMzduLSw4+5v5uyxW+8+mbtt3vibcTNmvmoB486pr43uBfyFzH3Vvm+Qty5Gaq6TWerH6tPf8dtfm94X0/oIt1ZX1Z8nVqkJVpytvPTuzwGIiDMlyAAAgAElEQVS1D52cP3/bmSOXGy7XtTQLnvPVTav3l3+w4mC/MVmDJ+Yu33vJ7RVVqEerIWK62bUqknERQAABBBBAwKACJH+6Xq5THAIIIIAAAnILkPzJLUp/CCCAgC4FSP7UWaJ3m/yp87TPThP03Tju/PZ/BFuqc/WrktDY6aiMX5sE98drj1is9hfm7jxdeStcz4fL64Ppzl/WHmlzqRFGhqskyfd7T2cLUwcI0x9y75ktudq61ZCaq907pgi2NMeXw8TqU922kWWnJEnL915KHZv1pG3r1hPXPb7ug72LNc3/s6TIYrX/ck5h1S0tH0Yqy6zDdULyF06G/QgggAACCCCQuADJny6X6RSFAAIIIICAUgIkf0rJ0i8CCCCgKwGSv8RXy9H00G3yl5ubO3z4cEmSiouL+/fv7/f7vV7vXXfddfnyZbfbnZKScvr06XCdJxgGeI+vF6YOcHz+pFhdFm6IRPbXNTuem1nQb0zW59vPhIttQv27vL752870G5P18oLdTYL5H94YmrheNiTJc2BRIAxe8ZLUXN1jVb6rBxxzHxWmDvCWfttj4zgaOD2+kcuKLVb7+8uLo/n3UFhWNeiT3CembD1f3RTHcPo/JcGbXf8TpEIEEEAAAQQQ0FCA5E9Xy3OKQQABBBBAQGkBkj+lhekfAQQQ0IUAyZ8Ky+yXX375P/7jP/7hH/7hP//zP5csWbKw/eP3+yVJeu+993r16nX//fcfOXIkWEleXt7dd9/dq1evyZMnR6gt8TDAd/1YIL+ZPtBXWRJhoDgO1TQ5np1R8NCEnEPl9dGfXlhWlTY2+5dzChtandGfRctEBUTRtWV84Bmem0b6PdHKS631ztW/E2yp3hMbEy3g++e7veK7Xwfe6rdy3yVJkr5/MOy3c1VNj0/JH/RJ7sFLdWEbGfZA4je7YadO4QgggAACCCCguADJny6W5RSBAAIIIICAWgIkf2pJMw4CCCCgqQDJn+KLaWUGkCUMkJqrHV/81DH7EbG+XK4yq5uEp6dvHzghp+RKQ6x9Fl2oHTA+59mZBXXNjljPpX18Au4dNsGW6i6Y7Be7f6Jm2G49TufqVwVbmvfslrBtYjzg9YkfrjpksdrXH7wS46n+G7eEX8za0X9c9qlKBZ9hG2tVsrSX5WaXpRI6QQABBBBAAAHzCZD8abocZ3AEEEAAAQTUFiD5U1uc8RBAAAFNBEj+DLp6lysMEBsuO2Y/4vj8SalVhh9LCW7v87MLB32Se+zqzfhgS640PDQh59Uv9ri9MQZR8Y2X3Gd5S9cFfu2XN84f9a/rOoJJrjbnsl8LU/v7Lu3uuD++bUmSRq87arHal++9FF8PDa3OYenbHp+SX9NkquRYrps9PlXOQgABBBBAAAFzC5D8abIMZ1AEEEAAAQS0EiD500qecRFAAAFVBUj+DLqSlzEM8F0vFaY/5FzyC8ktJKIhSZL1m6MPjs4sulCTSD9bjldarPZJm0sT6YRzexTwXT0gpPd3rnnN7/P02DhcA8lxy7H4OWHmYLGxIlybKPcv33vJYrV/sf1slO27bXauqmnghJzfzN/lcPu6bWDEnTLe7EacPjUjgAACCCCAgKICJH+qLr8ZDAEEEEAAAa0FSP60vgKMjwACCKgiQPKn6EJauc7lDQO85wvaf/s1NpGC1xaVW6z2hQUJJTfBAmbmnrJY7ZsOX02kHs6NICA2VjhmP+xY9JTkaIrQLJpDYmOFMHOQc+mvEkkQT1U2po7NGrW8OPp3+4WrbWdZ1YOjMz9cfTjxrsINofJ+eW92lYtnOAQQQAABBBDQuQDJnyrLbgZBAAEEEEBALwIkf3q5EtSBAAIIKCpA8qfzpXi48mQPA9wFkwVbqvfCjnAjRt5/vOJm6tisPy49IIpS5JbRHPX6xBGL96WNyy67fiua9rSJTUAUnateEWYMEhsux3ZimNbespzAywIL08Mc72F3i9MzfNr2n9q2NgnuHppGd3jxznMWq32zWZJj2W/26BRphQACCCCAAAJJIUDyp+hym84RQAABBBDQmwDJn96uCPUggAACigiQ/Bl0QS9/GOB1ORY/55gzRGqtj9XE4fYNn7b9Z1O3NQvxPzey06CNbe7Hp+S/MHenx8cL/zrZJPrVc2iZYEv1lKxJtKMO57tyrYItNY4X/kmS9OfVh/uNySq50tChv4Q2RVF6/cu9gyfmmuOFf/Lf7AnpcjICCCCAAAIImEqA5E+RZTadIoAAAgggoFcBkj+9XhnqQgABBGQVIPkz6MJdiTBArDkrTB3gXPe2X4rtd3uz8k5brPZD5TFHhpHxC07dsFjtGYXnIjfjaEwCYsPlwGsd1/4+1qsceRTJLTgWPe2Y+6jkbIncstPRrSeuW6z2RTtkeEhsx56v1rcOGJ/9h6+LTPDMTyVu9o5WbCOAAAIIIIBAMguQ/Mm6vKYzBBBAAAEE9C5A8qf3K0R9CCCAgCwCJH8GXecrFAZ4Di0JPPPzxKboWc7eaOo3Jmv8+pLoT4m+5YerDqWNyy6viy1Mir7/pGsp+pwrXhJmDpaabsg+d9+N44Fnfm6bFH3PbS7vE1O2/mruTq8Cv+xcue+SOd4WqdDNHv1loiUCCCCAAAIImFggmPxF+X+Li4tPnjx54cKFioqK69ev19TU1NbW1tfXNzQ0dF1XyrJcpRMEEEAAAQQQkFeA5E9eT3pDAAEEdCrQdYXW0NBQX19fW1tbU1Nz/fr1ioqKCxcunDx5sri42MQrXsNNTakwQBSdX78Q+OWWqzUaE58ovbxg96OfbpHrDW2dBq1rcQyemPv6wr2yvD6wU+dJ+NVzZGUg2T2+XqG5u/LGCrY0sbosyv6n55y0WO2lFTejbB9Ts8AzPxfuHfRJbn2LM6YT9dZYqZtdb/OkHgQQQAABBBDQQiDKzC/YjORPp6t6ykIAAQQQQCBqAZK/qKloiAACCBhZgORPi/W1DGMqFwb4rh8L/HKrMD2aKle1/6wq59i1aBrH12bToasWq33joSvxnc5ZIQHJ2eyYPcS58rfyPucz1L/f75eERsfsR5zLfxPNEBeqm/uNyfpk47GOPci7fbmupX2IUnm7Vbk35W52lSfCcAgggAACCCCgQwGSPyOv5qkdAQQQQACBmAVI/mIm4wQEEEDAiAIkfzpcfkdTkqJhgCvr/4Sp/cWGy5ErudXmHjwx9+2v9iv6KjVJkn73xZ6hk/MFtzdyPRyNLOAumCLYUsWqE5GbJXjUc+ybaH5WKEnSa1/uGTIp71abO8ERI59uyzrRd3TmhermyM30fFTRm13PE6c2BBBAAAEEEFBBgOTPiKt4akYAAQQQQCBuAZK/uOk4EQEEEDCSAMmfCstpJYZQNAyQWmqEGQOd696OXPn0nJPqZCrHrjZYrPYvC85GroejEQTEm1eFqf1d2R9FaCPPIVF0LnvRMWeI5GqL0OGW45Xq/JSzSXA//Ne8/1lSFKEYnR9S9GbX+dwpDwEEEEAAAQSUFiD5M9LqnVoRQAABBBBIWIDkL2FCOkAAAQSMIEDyp/RaWqH+lQ4DPAcWCrZUX/mecPXfuCWkjcse+21JuAby7v9gxcGBE3IaWo39wjZ5TWLqzbXxj8L0gVJzdUxnxdc4+MBYz7554U73+sRnZxQ8P7vQJ0rh2si4f9meixarfe85NeYuY9mhrpS+2UMDsYEAAggggAACSShA8meEVTs1IoAAAgggIJsAyZ9slHSEAAII6FmA5M+gy3vFwwCv27HgCefSF8K9sG3styVp47Jv3BLUASxvf2HbZPtxdYYz2Si+a4cD727cO1e1eTnXvS3MHCw5bnU74qbDgXc3Fpy60e1R2Xe6veLT07f/YtYOr0+UvXMVOlT8ZldhDgyBAAIIIIAAAnoVIPnT82qd2hBAAAEEEJBdgORPdlI6RAABBPQoQPKn1zV4D3WpEAZ4StYEXth2obBrKRdrmvuOzpyec7LrIeX2TNpc2m9M1pX6VuWGMGvPztWvOuY+KrlVimn9fr9YfTqQNe6c3pXU5fUNS9/28vxdir4estO4205et1jtmUcqOu03xFcVbnZDOFAkAggggAACCCghQPKnx1U6NSGAAAIIIKCYAMmfYrR0jAACCOhJgORPifWzCn2qEQb4PI7Pn3B+/cuuP/sbuax40Ce5t9rcKsw0NER9i/OhCTl/WXsktIeNaAR8FYcEW6rn4FfRNJaxjWvTqMDzRVvrO/W5en+5xWovulDbab+iX0VR+uWcwmdnFKjzfFF556LGzS5vxfSGAAIIIIAAAsYRIPnT0+qcWhBAAAEEEFBcgORPcWIGQAABBPQgQPJnnFX59ypVJwzwHFsb+Nnf+YKOY5+90WSx2r8sONtxpzrbM3JP9R2dea2hTZ3hzDGKc83rjjlD1PzBX9BNrL8k2NLc2z7tyCi4vY99lv/7RXvV/MFfsID8E4Gf/eWWVnasxxDb6tzshqCgSAQQQAABBBCQXYDkTw+rcmpAAAEEEEBANQGSP9WoGQgBBBDQUoDkT/bFc9cO8/Pz+/Tp07t37/T09I5Hp0+fbmn/3HfffX//939/8+ZNv99/55133n///RaLJfKf+yMf7ThKQts+j+OLJ51LftHxZ3//t+bIoE9ymx2ehHqO6+S6Zkfa2OyJm0rjOjsZT/JVlgR+8HdgoSaTd2V/JEwdILX87ed9y/desljtJVca1K9HFKWfz9rx/OwdoiipP3oiI6p0sydSIucigAACCCCAgGEFSP60XI0zNgIIIIAAAqoLkPypTs6ACCCAgBYCJH9KL9J9Pl+vXr3Ky8vdbndKSkpZWVnXEbOzs4cOHRrcf+edd9bXd35AYtdTVAsDvKXfBn72d25bsIar9a19R2fOzD3VtSR19vx1U2na2OyaJoc6wxl9FOc3bzlmPyK5tPmVpNhwuf1tf9OCjB6f+FPb1jcW7tVKNbvkmsVq337yulYFxDeuajd7fOVxFgIIIIAAAggYWoDkT4tVOGMigAACCCCgmQDJn2b0DIwAAgioKUDyp/RC/cCBA8OGDQuOYmv/dB3xt7/97eLFi4P79Zb8+X3ewNv+VrwULG/iptK0cdl1zZoFb9ca2vqNyZqWfbIrI3s6CfhuHA/84G//gk771fzq2vCuY9ZgydXq9/uzSyosVvues9VqFtBxLK9PfHr69l/N3an+s0Y7lhHrNslfrGK0RwABBBBAAIHoBUj+1Fx9MxYCCCCAAAKaC5D8aX4JKAABBBBQQ4DkL/pVcXwtN2zYMGLEiOC5K1euHDlyZKd+BEH453/+5+CjPv1+/49//OO+ffv269cvIyOjU0u/35+RkZHa/rnjjju6HlVoj+fgV4It1Xe9VCcP27R+c3TA+JxbbW6F5muabl0b3wukbs4WDWfku34skD4e/EqSpF/OKXx+9g5tU7dNh68G0sdzmqWPcVwLkr840DgFAQQQQAABBKIUIPlTY9XNGAgggAACCOhGgORPN5eCQhBAAAElBUj+olwSx91s/fr1HZO/UaNGdepq3bp1zz77bGjnjRs3/H5/bW1tSkrKnj17Qvs7bagZBkiuVmHmYNemkTNzT/UdnVnREPj9loafizXNFqt9/rYzGtag/6HFW9cEW5p7xxTNS3WueNmx4PG9ZyotVrv9SIW29bi94tDJ+W9/tV/bMmIaXc2bPabCaIwAAggggAACJhAg+VNytU3fCCCAAAII6E6A5E93l4SCEEAAASUESP6UXq73+LTP559/fs2aNV3LmDhx4owZM7ruD+5ROQxwF0xps6U9N2HZn1cfDleSmvtHLjvw6KdbXF6fmoMaayx3wRTBlibeqtS8bO/5AsGWumCO7YkpW91eUfN6Fu04a7HaL9Y0a15JlAWofLNHWRXNEEAAAQQQQMAcAiR/Sqyy6RMBBBBAAAHdCpD86fbSUBgCCCAgpwDJn9Irdq/Xe9ddd12+fNntdqekpJw+fbrjiE1NTf/8z//c1tYW3NnW1tbSEng2Y1tb26BBg/Lz8zs27ritchggNd1otaUtGv/qyWuNHcvQarvoQq3Fas/U+gdkWk2/x3ElV1vwZ5o9tlSjgSjeWjDs2KT/XrrrvBrD9TTGzVZX/3HZEzeV9tRQL8dVvtn1Mm3qQAABBBBAAAFVBEj+5Fxd0xcCCCCAAAK6FyD50/0lokAEEEBADgGSPxUW1Hl5eXfffXevXr0mT57s9/sXtn+C4y5btuyll14K1VBeXp7S/rn33nuDjUOHOm2oHAaIopQ35cUGW3/JqYtfSkmS9PNZO34zf5e2L43rdFH089VzeHng1YyVJTopae0im2BLbTm/Wyf1jF9/bMD4bKO8KlLlm10n14gyEEAAAQQQQEAdAZI/OVbV9IEAAggggIBhBEj+DHOpKBQBBBBIRIDkT50VteyjqBwG7D9f87x1nmBL9RRnyD6X+Dpce+CyxWo/dvVmfKeb+SxRdHw5zLn0VzqZY2Obe9C4jQ3pA10b39NJSeermyxW++Kd53RST+QyVL7ZIxfDUQQQQAABBBAwmQDJXyKrac5FAAEEEEDAcAIkf4a7ZBSMAAIIxCNA8mfQpbvKYcB7Sw889tkWYflvHF8O84vav6ot8EBUl3fwxNz/W3PEoFdQubKD79XznspUboiYel6y67zFaq/OnCCk95eaq2M6V7nGIxbve2LKVo9PF/+YI09T5Zs9cjEcRQABBBBAAAGTCZD8xbOK5hwEEEAAAQQMK0DyZ9hLR+EIIIBALAIkfwZduqsZBlxraHtwdOa8rWXek5sDz5As36MTtKnZJ/uNyaptduikHp2U4Vz7e8e8x/w+jx7q8YnSz6Zu+/2iveLNK4It1b1njh6q8vv9u85UWaz2LccrdVJPhDLUvNkjlMEhBBBAAAEEEDClAMlfLKtn2iKAAAIIIGB4AZI/w19CJoAAAghEI0DyZ9AFvJphwPScQMBW0+Twe5yO2Y+4NryrE7SKhtYHR2fO31qmk3r0UIbYWBEI2HbP1kMxfr9/99lAwJZ/4rrf79dbJDksfduIxft0AhWhDDVv9ghlcAgBBBBAAAEETClA8hfNqpk2CCCAAAIImEaA5M80l5KJIIAAApEESP4MuoBXLQxwuH2DJ+Z+uOpwEMpdMEWwpennmY1/XHpg6OR8rxGe2ajOvzT3zumCLU28pZefsr37ddHQyfnBh2p6z28XbKneM3nqUPQ4ysKCsxar/Wp9a48ttW2g2s2u7TQZHQEEEEAAAQQ0ESD5i7Ra5hgCCCCAAAKmEyD5M90lZUIIIIBAdwIkf5ossBMfVLUwIOtohcVqP3ipLliz2HA58JOyvfMSn4IsPew4fcNitReWVcnSm+E78Xkccx91fvOWTiYSfE7sgm1nvqtH9DkWPOFc/apOyqtpcvQbkzUr77RO6glXhmo3e7gC2I8AAggggAACJhYg+etulcw+BBBAAAEETCtA8mfaS8vEEEAAgY4CJH8GXcarFga8sXDv09O3S5IUgnKuec0x/3G/6Avt0XDD4xOHTs4fueyAhjXoZ2jv2S2BH9Wd366TkmZvOd3pRYye/Z8LtlSx/pJOKhy1vPixz7a4vaJO6um2DNVu9m5HZycCCCCAAAIImFuA5K/j6phtBBBAAAEETC9A8mf6S8wEEUAAgYAAyZ9BV/LqhAFX6lstVntG4bmOSt4zee3xUkHHnRpuz95yuu/ozMBrCJP+c/tFel49SHi/C2WLOxYjtdYJtjT3DlvHnRpu7zlbbbHat7a/hlDDMiIPrc7NHrkGjiKAAAIIIICAWQVI/vi7AAIIIIAAAkklQPKXVJebySKAQPIKkPwZdA2vThjQ9TdbAa7gIyXXva0TuoqGQDy5aMdZndSjVRliY0XgQay7Z2tVQKdxd5+tsljtO07f6LTf+e3/OOY+6vfpIp70idJPbVvf/mp/pyJ19VWdm11XU6YYBBBAAAEEEFBNgOQvef8WwMwRQAABBJJSgOQvKS87k0YAgeQTIPlTbVEt70AqhAG3f7PVzYM03Ttsgi1Nav3u5X/yTi2O3t7K2Dd82jZR/NsjSePoxOinuHfNEGxp4q1KnUzkgxUHH/tsi8fX+UGa3nNbdfWb0S+2n7VY7dca2nTi1rUMFW72roOyBwEEEEAAAQSSRIDkL/n+BsCMEUAAAQSSWoDkL6kvP5NHAIHkESD5M+iSXoUwoLAs8JutwrKqrkRi3QXBluopzuh6SJM9OceuWaz2ogu1moyui0FF0TH/cefaN3VRjN9/s9XVb0zWjNxT3dTj8zjmDHFteLebQ1rsqm4S+o7OnLe1TIvBoxpThZs9qjpohAACCCCAAAJmFCD5S561PzNFAAEEEECgsbGR5I9/BggggEBSCJD8GXT9rkIYMHLZgaGT871dfrMVFHMu/ZUj41m/pIuf2Tk9vkcm5X24+rBBr2biZfsu7w38kO50VuJdydLDsj0XLVb7xZrmbntzb/9MSO8vtTV0e1T9nW9/tX9Yun5/M6rCza6+OSMigAACCCCAgE4ESP6SYtnPJBFAAAEEELgtQPJ3W4L/IoAAAqYWIPnTyZI71jKUDgPqmh39xmTN3nI6XGGeIysFW6pYdSJcA5X3T8k8kTYuu9nhUXlcnQznyvxQmDnY73HqoR5Jkp6fveOVz3eHK0asPRf4zejBxeEaqLw/+JvRg5f08vTaTtNX+mbvNBxfEUAAAQQQQCCpBEj+TL3cZ3IIIIAAAgh0FiD56yzCdwQQQMCUAiR/Bl3YKx0GBH+zVV7XEs5HcjQJUwe48yeEa6Dy/pPXGi1W+4aDV1QeVw/DSa5WYfpDrtzReijG7/efaL8W6yNeC139ZtTh9g36JHfstyU6AexUhtI3e6fh+IoAAggggAACSSVA8mfKZT6TQgABBBBAIJwAyV84GfYjgAACphIg+TPowl7pMOBXc3e+PH9XZBzX5vcdsx/2e12Rm6lzVJKkZ2cWvP7lXnWG09Uo3tJvBVuq79oRnVQ1aXPpgPHZrc5Iv7/0HF0VqPnGcZ3UPH59ycAJOYLbq5N6Opah9M3ecSy2EUAAAQQQQCDZBEj+TLW8ZzIIIIAAAgj0JEDy15MQxxFAAAFTCJD8GXRtr2gYcKG62WK1r9p3KTKO79KuwLvlynIiN1PtaEbhOYvVXnmzTbURdTKQc9Urji+H6eSdi26v+MikvI/W9BBDfveb0a1/1Ynh4fJ6i9WeXVKhk3o6lqHozd5xILYRQAABBBBAIAkFSP5MsaxnEggggAACCEQrQPIXrRTtEEAAAUMLkPwZdHmvaBgwM+9UvzFZN1t7+jGf6HPMe8y5boRODK83tlms9i8LzuqkHnXKEBsrBFuqe+88dYbrcZSdZVUWq3332aoeW7o2vOuYM8Tv08XP7ERRGj5t24jF+3ssW/0Git7s6k+HERFAAAEEEEBAVwIkf4ZezlM8AggggAACsQqQ/MUqRnsEEEDAkAIkfyosvPPz8/v06dO7d+/09PSOw+3atesf//EfLe2fSZMmBQ+Fa9zxRL/fr1wY4BOlJ6ZsfW/pgU4jdvvVXTBZSO8vCY3dHlV/5xsL9z4zo0CSJPWH1mpE9955gi1VbNTLj9U+XH34vz/d4vGJPYJ4z24JPPDzUg8Ple2xH7kaLNh25sHRmdVNglwdytWPcje7XBXSDwIIIIAAAggYV4Dkz5DLeIpGAAEEEEAgXgGSv3jlOA8BBBAwlADJn9KrdJ/P16tXr/LycrfbnZKSUlZWFhpx165dzzzzTOir3++P0LhjM0WTvwMXay1W+5bjlZ1G7ParWH1KsKV6jqzs9qj6Ozcdumqx2o9X3FR/aG1GlCTHwuHOlb/VZvQuo7Y6Pf3HZU+2R/f2Pq/LMWuwK/N/u3SjzY6KhlaL1f7VzvPaDB9+VJK/8DYcQQABBBBAAIFEBUj+DLV8p1gEEEAAAQQSFSD5S1SQ8xFAAAFDCJD8JbpW7un8AwcODBs2LNjK1v4JndE1+YvQOHRWcEO5MGDMupJBn+Q6Pb5OI3b/VZIci55yrni5+6Oq7w0mT59uji55Ur082QcUq04EkteSNbL3HF+Hmw8HktfSqJNXV65VmD5QcuvlZ3avfL77hbk745u7cmcpd7MrVzM9I4AAAggggIBRBEj+DLFsp0gEEEAAAQTkEiD5k0uSfhBAAAFdC5D8Kb0m37Bhw4gR370Jb+XKlSNHjgyNuGvXrn/5l39JSUkZPnz46dOn/X5/hMbBszIyMlLbP3fccUeoHxk3HG7fwAk549eXRN/nd0+bvBXVbwSj7zbuln9efXjIpLxonjYZ9xD6OVFvT1sdsXjfU9O3R/+0Vd/VYsGW6j2VqRPSVfsuWaz2izXNOqknWAbJn64uB8UggAACCCBgMgGSP10v1ykOAQQQQAABuQVI/uQWpT8EEEBAlwIkf0ov3devX98x+Rs1alRoxObm5tbWVr/fn5eX95Of/MTv90doHDoruKFQGJBXWmmx2g9equs0XISv4s2rgZ+dFX0RoY2ahwrLqixW+95z1WoOqs1YouiYP9S57m1tRu8yam2z48HRmQu2nelyJPyOwBQed37zVvgWqh6pb3H2HZ05b+vfHsmr6vBhBlPoZg8zGrsRQAABBBBAILkESP50uUynKAQQQAABBJQSIPlTSpZ+EUAAAV0JkPwpvbKP8gGed955Z319fZSNlXvP3/vLi4dOzveJUkwszmW/dix+LqZTlGvs8voGT8wdsy6Gny0qV4yiPevtB3NLd1+wWO1X6gNhdvQfd2G6YEuT2hqiP0XRliMW74/pZ4uKFhPsnORPBWSGQAABBBBAIGkFSP50tTynGAQQQAABBJQWIPlTWpj+EUAAAV0IkPwpvcj3er133XXX5cuX3W53SkpK8KmewUGrq6uDz0U8dOjQj370I0mSIjTuVKcSYUCL05M2LtuWdaLTWD1+9RxaJthSxZqzPbZUp8G4b6LwkesAACAASURBVGN5VaE6NSkwiit3jDD9If28JO8383e9PH9XrBMVa84GfjN6eHmsJyrUftOhwKsKT1xrVKj/OLpV4maPowxOQQABBBBAAAFTCpD86WJZThEIIIAAAgioJUDyp5Y04yCAAAKaCpD8qbCAz8vLu/vuu3v16jV58mS/37+w/eP3+xcsWHDvvfempKQ89NBDRUVFwUo6NQ5XnhJhQOaRCovVXlpxM9yg4fZLrXWCLc1dODVcA5X37z9fY7Hat5+6ofK4qg7ndTtmP+za/IGqg4Yf7Gp9q8VqX7r7QvgmYY84Mp5xrvxt2MPqHmh2eNLGZqdnnVR32EijKXGzRxqPYwgggAACCCCQTAIkf5ouxxkcAQQQQAABtQVI/tQWZzwEEEBAEwGSP4Ou65UIA/7wddGw9G3BnyHGyuJc84bj8yf9UmyPCY11lCjbe33io59u+XD14SjbG7GZ98IOwZbqPb9dJ8VnFJ6zWO1Vt4Q46nHvmSPYUqVmvbyacVRcz7yNY+JRnqLEzR7l0DRDAAEEEEAAAdMLkPxpsgxnUAQQQAABBLQSIPnTSp5xEUAAAVUFSP4MupiXPQy41ebuNyZrZt6p+EA8x74JPPCzKuYnhcY3XI9nfbr5+IDx2W0ub48tDdrAZf+TY9Zgv9etk/p/Oafw1S/2xFeMWH8p8MDPQ0viO132s7Ycr7RY7Qcv1cnec3wdyn6zx1cGZyGAAAIIIICAKQVI/lRdfjMYAggggAACWguQ/Gl9BRgfAQQQUEWA5M+gC3jZw4D1B69YrPay67fiA5GERiG9v3vHlPhOl/2sI5cbLFZ7zrFrsvesiw49DmHGQFfOx7ooxu+/VNtisdpX7rsUdz2OxT93Ln8x7tPlPdHh9j00IeeTjcfk7Tbu3mS/2eOuhBMRQAABBBBAwHwCJH+qLLsZBAEEEEAAAb0IkPzp5UpQBwIIIKCoAMmfQVfvsocBb2Xse3ZGQXyP+gwaOte+6fj8CZ088FMUpSdtW0cuO2DQ6xu5bO/ZfMGW6ru0O3Iz1Y5+vv3Mg6Mza5sdcY/o2b8g8MDPputx9yDviX9effi/P93i9Ynydhtfb7Lf7PGVwVkIIIAAAgggYEoBkj9Fl9t0jgACCCCAgN4ESP70dkWoBwEEEFBEgOTPoAt4ecOAuhZH39GZ87edSUTDW/ptII66UZpIJzKeOy37ZOrYrGaHR8Y+ddKVy/6BY/bDfp9epvaLWTteX7g3ERzx5pXAAz+LMxLpRMZzt528brHaD1yslbHPuLuS92aPuwxORAABBBBAAAFTCpD8KbLMplMEEEAAAQT0KkDyp9crQ10IIICArAIkfwZdwMsbBqwpKrdY7RdrmhPRkBy3Ag/8LJicSCcynltacdNitWcdrZCxT1105XEKMwbp51GfF6qbLVb72qLyBHGcS553fv1Cgp3IdXrwgZ8TN+kixpb3ZpeLiH4QQAABBBBAwBwCJH+yLq/pDAEEEEAAAb0LkPzp/QpRHwIIICCLAMmfQVfs8oYBv1+09+ezdiRO4fzmLceCx3XywE9Jkn4aeOBnceLz0lUP3nNb2x/1uUsnVc3bWtZ3dGZ9izPBejwHFgq2VLFRL0ntn1cfflQfD/yU92ZP8DJxOgIIIIAAAgiYTIDkT5ZlNZ0ggAACCCBgFAGSP6NcKepEAAEEEhIg+TPo0l3GMKC+xRl41OfWssQpvMc3BEKp68cS70qWHtKzTqaNy2516uWpmLJMSleP+pQk6dmZBW9l7Et8amJjReCBn0VfJN6VLD0EH/hZrIMHfsp4s8siQycIIIAAAgggYCYBkr+EltOcjAACCCCAgNEESP6MdsWoFwEEEIhLgOTPoOt2GcOAdcWXLVb7uaqmxCkkR5Mwtb97+2eJdyVLDyVXGixWe86xa7L0potOdPaoz4s17Y/6PHBZFhzn1y/o6oGfA8bn/FUHD/yU8WaX5TLRCQIIIIAAAgiYSYDkL65lNCchgAACCCBgVAGSP6NeOepGAAEEYhIg+TPoul3GMGDE4v3PziiQJEkWCue6tx3z9fLAT1GUHp+S//5y8zzwU2+P+vx8+5kHR2fWtThk+cfjKfoi8MDPW5Wy9JZ4Jx+uPvzYZ1t8ojy3Rtz1yHizx10DJyKAAAIIIICAWQVI/mJaPtMYAQQQQAABowuQ/Bn9ClI/AgggEJUAyZ9B1/ByhQGNbe5+Y7Lm5J+Wy8F7fH37Az9L5eowwX6mZJ5IG5fd5vIm2I9OTnfZ/+SY/bDfp5fnl/5yTuHrX+6VC0dsuBx44OfBr+TqMMF+tp64brHaD16qS7CfBE+X62ZPsAxORwABBBBAAAFTCpD8RbVsphECCCCAAAJmESD5M8uVZB4IIIBARAGSP4Mu4OUKAzYeumKx2suu35LLQRIahfT+7h02uTpMsJ8jlwMP/Mwr1cvPyBKajtclzBzkyvk4oU7kO/lyXYvFal+x95J8Xfodi59zLv+NjB0m0pXD7RswPmfSZo1jbLlu9kQoOBcBBBBAAAEEzCpA8hdxucxBBBBAAAEEzCZA8me2K8p8EEAAgW4FSP4MuoaXKwx4Z0nR8Gnb5XrUZxDTueY1x5fD/DI9PjTBC+QTpaGT8/+08lCC/ejhdO+FQsGW6r1QqIdi/H5/RuE5i9VedUuQsR733rmCLVVqqZGxz0S6+nDVoaGT80VNH/gp182eiAPnIoAAAggggIBZBUj+ul0msxMBBBBAAAGzCpD8mfXKMi8EEEDgewIkfwZdw8sSBjQJgUd9zsw7JS+C5+iqwNvaqsvk7Tbu3j6zHx8wPltwG/6Bn66cj4WZg/xeV9wU8p744rydLy/YLW+fYu35wAM/Dy+Xt9u4e8s5ds1itR+72hB3D4mfKMvNnngZ9IAAAggggAACphQg+fve8pgvCCCAAAIImF2A5M/sV5j5IYAAAu0CJH8GXcDLEgbYj1RYrPYT1xrlRZBa6wRbqnv3LHm7jbu34ou1Fqt9+8nrcfegixN9XsfsR1z2D3RRjN9febPNYrUv3X1e9noci55yrnpF9m7j67DV6Ukbmz0952R8p8tyliw3uyyV0AkCCCCAAAIImE+A5I8/DCCAAAIIIJBUAiR/SXW5mSwCCCSvAMmfQVfvsoQBI5cVP2nbKu+jPoOezpW/dWQ8oxNbr098ZFKe9ZujOqknvjJ8V/YHHvV5Jje+02U/a+nu8xarvfJmm+w9u3fNEGxpUpuWP7PrOKl3vy762dRtStwmHUeJsC3LzR6hfw4hgAACCCCAQDILkPwl798CmDkCCCCAQFIKkPwl5WVn0gggkHwCJH8qrPPz8/P79OnTu3fv9PT0jsOtXr36gfbPoEGDjh8/Hjx055133n///RaLJfKf+yMf7ThKuO02l7f/uOwpmSfCNUhkv+fQ14EHftZfSqQTGc8d923J4Im5bq8oY58qd+XOnyBMe0hyy/lSvUSm8Mrnu389d2ciPYQ7V6w+FXjgZ8macA1U3r/x0BWL1V52/ZbK44aGS/xmD3XFBgIIIIAAAggg0EmA5C/5/gbAjBFAAAEEklqA5C+pLz+TRwCB5BEg+eu09JX9q8/n69WrV3l5udvtTklJKSv729vvioqKGhsDT9rcsmXLgAEDgkPfeeed9fX1PZaReBiw9cR1i9V+8FJdj2PF0UBquh4Ib/YviONcJU7ZWVZlsdr3n69RonM1+hRFx7zHXOv/oMZYUYxR2+ywWO0LC85G0Tb2JpLk+OJJ59o3Yz9TkTMa29x9R2fO2/q3O1eRYcJ3mvjNHr5vjiCAAAIIIIBAsguQ/CXP2p+ZIoAAAggg0NjYSPLHPwMEEEAgKQRI/pRe6x84cGDYsGHBUWztn64jNjY2/vCHPwzuVy35+3jtkSGT8rw+pX4G51z6gnPJ810nq8kep8f30ISciZtKNRk98UF9lSWBR32e2JR4V7L0sPbAZYvVfrGmWZbeunbi3v6ZMLW/5GzpekiTPW8u2veLWTs0Gdrv95P8aSXPuAgggAACCCSDAMlfUiz7mSQCCCCAAAK3BUj+bkvwXwQQQMDUAiR/Sq/nN2zYMGLEiOAoK1euHDlyZNcRZ8yYEWrz4x//uG/fvv369cvIyOjaMiMjI7X9c8cdd3Q9Gv0et1cc9Enu+PUl0Z8Sa0tP0ReBB37eqoz1RIXaf7jq8GOf5ftESaH+Fe3WXTBFSO8vOZoUHSX6zt/+av8zMwqUe/Wdr+JQIOk8lRl9SYq2XL2/3GK1X6rVJokk+VP04tI5AggggAACSS5A8mfq5T6TQwABBBBAoLMAyV9nEb4jgAACphQg+VN6qb9+/fpQqrdy5cpRo0Z1GnHnzp333HNPQ0NDcP+NGzf8fn9tbW1KSsqePXs6NQ59TTAM2Huu2mK17zpTFepQ9g2xvjzwwM9DS2XvOb4Oc0srLVZ7yZXvnOPrRJuzAk+//KlzzRvajN5l1GbB029M1sy8U12OyLdD9DnmDHFt6iYml2+MGHqqbhIsVntG4bkYzpGvaYI3u3yF0BMCCCCAAAIImFCA5M+Uy3wmhQACCCCAQDgBkr9wMuxHAAEETCVA8qf08j3y0z5PnDjRq1ev8+fPdy1j4sSJM2bM6Lo/uCfBMOCTjaUDJ+Q4Pb5w/cuy37HoKeeqV2TpKvFOWp2etLHZ07JPJt6Vyj2INWcCGerRVSqPG2647JIKi9VeWnEzXANZ9rtyrcKMgX6PU5beEu/k5QW7fzN/V+L9xNFDgjd7HCNyCgIIIIAAAggkjwDJn6mW90wGAQQQQACBngRI/noS4jgCCCBgCgGSP6VX9V6v96677rp8+bLb7U5JSTl9+nRoxIqKit69excVFYX2tLW1tbQEnijY1tY2aNCg/Pz80KFOG4mEAT5ReuyzLR+uPtypT9m/undOE2xpktAoe8/xdfju10XDp21T7hmV8VXV41nuvXMFW6rUUttjS3UafLDi4NDJ+aLCz031XdwZeODnBc3ertcJ86ud5y1We9UtodN+Fb4mcrOrUB5DIIAAAggggIChBUj+TLGsZxIIIIAAAghEK0DyF60U7RBAAAFDC5D8qbBQz8vLu/vuu3v16jV58mS/37+w/eP3+0eMGPGDH/zA0v4J/nG/vLw8pf1z7733BhuHKy+RMODolQaL1Z5Xqvgb+Hw3jgfCm+Prw81C5f0bD12xWO1nbtxSedwEh3Mu+YVz+YsJdiLX6Q63b8D47EmbS+XqMGw/XpcwY5Ar5+OwDdQ9UF7XYrHa1xSVqztsYLREbnb1q2VEBBBAAAEEEDCWAMmfoZfzFI8AAggggECsAiR/sYrRHgEEEDCkAMmfsVbmoWoTCQOm55xMG5vd6vSEelNqQ5Ic84c6v31Hqf5j7Leh1fng6MzPt5+J8Twtm4u3KgOP+jywUMsiOoxdcOqGxWovulDTYZ9Sm67N7ztmD/GLyj6TNvrqn5tZMGLx/ujby9UykZtdrhroBwEEEEAAAQTMKkDyZ8hlPEUjgAACCCAQrwDJX7xynIcAAggYSoDkz6Br+LjDAEmSnpq+/Q9f/+0Ro4oKuPMnCNMektwaPCOx23m99uWeX83d2e0hfe70HPpasKWKDZd1Ut7odUcHT8z1+EQV6vGezhZsqb6KgyqMFc0Qs7ec7jcmq1lQPjL/fjVx3+zf74ZvCCCAAAIIIIBANwIkf4ZavlMsAggggAACiQqQ/CUqyPkIIICAIQRI/rpZ/hphV9xhwIXqZovV/m3xFXVm6bu8N/DAz7Nb1Bmux1GW7r5gsdorb7b12FInDZyrXnEselonxXh94iOT8qzfHFWnHsnVKkwd4N72qTrD9TjK8YqbFqs9u6Six5byNoj7Zpe3DHpDAAEEEEAAAVMKkPwZYtlOkQgggAACCMglQPInlyT9IIAAAroWIPkz6AI+7jBgYcHZB0dn1rU4VJq4z+OYNdiV9WeVhutpmKv1rRarfcXeSz011MVxSWgUbGnundN1UY3ff/BSncVq33byumr1OL95y/H5k35JUm3ECAOJovT4lPw/rTwUoY0Sh+K+2ZUohj4RQAABBBBAwGQCJH+6Xq5THAIIIIAAAnILkPzJLUp/CCCAgC4FSP4MunSPOwx4af6uVz7freasXZkfOmYN9vvUfkZiuDk+P7vw94v2hjuqq/3e4xsCj7u8cVwnVdmyTqSNy25zeVWrx1OyJvCw0xq9vJpx0ubShybkOD2qvnow7ptdtcvEQAgggAACCCBgXAGSP10u0ykKAQQQQAABpQRI/pSSpV8EEEBAVwIkfwZdpccXBlTdEixW+1c7z6s5a++ZvEB8dWW/moNGGGve1rK+ozNvtbkjtNHJIdf6PzjmD9XJL94kSfrZ1G1/XHpATRyppVawpbr3zlVz0Ahj7T9fY7Had52pitBG9kPx3eyyl0GHCCCAAAIIIGBKAZI/XS3PKQYBBBBAAAGlBUj+lBamfwQQQEAXAiR/Bl3AxxcGrCkqt1jt5XUtas5acrUF3ta29a9qDhphrFOVjRar3X5E7be1RSip20OSWxCmP+TaMr7bo+rvPHujyWK1bzio0hsiQxN0LnvRueT50FdtN9xecdAnuePXl6hZRnw3u5oVMhYCCCCAAAIIGFeA5E8Xy3KKQAABBBBAQC0Bkj+1pBkHAQQQ0FSA5M+gq/T4woARi/c/N7NA/SkH3ta24An9/HbtiSlb319erL5DTCN6z20L/FayfE9MZynX+IvtgTdE1rc4lRui2549RV8ItlSpSb2XC3ZbRmjnR2uOPPrpFp+o3qsH47vZQwWzgQACCCCAAAIIRBAg+dN0Oc7gCCCAAAIIqC1A8qe2OOMhgAACmgiQ/EVYBuv5UBxhQLPD029M1uwtp9Wf13dva6vWYOhuJ/uZ/fiA8dkOt6pva+u2kgg7XTkfCzN19H7EX8/d+eoXGsSQYv0lwZbqObw8gpWah/JKKy1We8mVBtUGjeNmV602BkIAAQQQQAABowuQ/GmyDGdQBBBAAAEEtBIg+dNKnnERQAABVQVI/gy6Vo8jDMg5ds1itZdW3FR/ylJrXeBtbXvmqD90tyMWXai1WO07Tt/o9qgudoo+x+whrs0f6KIYv/9G+xsiv96l6hsiQ3N3LBzuXPNa6Ku2G61OT+rYrJm5p1QrI46bXbXaGAgBBBBAAAEEjC5A8qfq8pvBEEAAAQQQ0FqA5E/rK8D4CCCAgCoCJH8GXavHEQZ8uOrw0Mn5oopPKexoG3hb21c/77hHw22PTxw8MXfct6q+rS2m+fquHRZsqd7T2TGdpVzjVfsuWaz2y+q+ITI0HfcOm5DeX3I0hfZou/H2V/ufmVEgSSo98DOOm11bH0ZHAAEEEEAAAQMJkPypsuxmEAQQQAABBPQiQPKnlytBHQgggICiAiR/BlqWdyw11jDA5fUNnJDzycbSjp2oue0p+lKwpYq3KtUcNMJY6r+tLUIxXQ+5CyYHsi5nS9dDmux5K2Pfz2ft0GRov9/vqzwayEFP2rUqoNO4a4vKLVb7pdrmTvsV+hrrza5QGXSLAAIIIIAAAqYUIPlTdLlN5wgggAACCOhNgORPb1eEehBAAAFFBEj+DLqAjzUM2Huu2mK17zlbrdV8v3tb26FlWhXQadzg29qOqvi2tk4FRPoqSY4vhznXvBGpjYrHmgXN3hD53SxF0TH3UdfG91ScdKShqpsEi9W+eOe5SI3kOxbrzS7fyPSEAAIIIIAAAuYXIPlTZJlNpwgggAACCOhVgORPr1eGuhBAAAFZBUj+DLqajzUM+Oum0ocm5Dg9Pg3nq8O3tc1Q8W1t0cuLdRcEW6rnyIroT1G0ZXaJZm+IDM3LlWsVZgz0e12hPdpu/Gb+rlc+361ODbHe7OpUxSgIIIAAAgggYA4Bkj9Zl9d0hgACCCCAgN4FSP70foWoDwEEEJBFgOTPoCv2mMIAUZQen5L/wYqD2k42yd/WFj2+Z//ngi1Vaq6K/hRFW2r7hsjg1LwXdgi2VN/FXYrONPrOvyw4++DozLoWR/SnxN0ypps97lE4EQEEEEAAAQSSU4DkT5ZlNZ0ggAACCCBgFAGSP6NcKepEAAEEEhIg+TPoCj+mMODktUaL1Z55pELbySb529qix3cu+7Xz619G317RlrffEHlM0VF67tzjFKYPdOWN7bmlKi3OVTVZrPb1B6+oMFpMN7sK9TAEAggggAACCJhJgOQvoeU0JyOAAAIIIGA0AZI/o10x6kUAAQTiEiD5M+i6PaYwYG5+Wb8xWbfa3BpPVvQ55gxxbRqlcRm3h1f5bW23h+3hv1JLrWBLde+d10M7tQ7vO19jsdp3n9X+B4iuDe865j3mlyS1ph5pHEmSfjZ12x+XHojUSKZjMd3sMo1JNwgggAACCCCQLAIkf3EtozkJAQQQQAABowqQ/Bn1ylE3AgggEJMAyZ8Ka/r8/Pw+ffr07t07PT2943CSJL3//vu9e/d+4IEHSkpKgofCNe54ot/vjykMeH524RsL93bqQZOvrpyPhZmD/F6tM8jbk1fzbW23x+zhv56SNYItVaw500M7tQ5P2lw6YLzGb4gMztV7fH3ggZ83jqs19R7GsWWdSBuX3eby9tAu4cMx3ewJj0YHCCCAAAIIIJBcAiR/MS2faYwAAggggIDRBUj+jH4FqR8BBBCISoDkT+mVvc/n69WrV3l5udvtTklJKSsrC42Yl5c3fPhwSZKKi4sHDBjg9/sjNA6dFdyIPgy41tBmsdqX7bnYqQdNvnrPbw+EN5d2azJ610HVfFtb19G73eP85i3H50/q55dtT0zZ+sGK4m5LVXmn1HZTsKW5d81Qedxwwx28VGex2refvB6ugVz7o7/Z5RqRfhBAAAEEEEAgeQRI/qJaNtMIAQQQQAABswiQ/JnlSjIPBBBAIKIAyZ/Sq/oDBw4MGzYsOIqt/RMa8Z133lm7dm3wa58+faqqqiI0Dp0V3Ig+DFi256LFar/W0NapB22+ehzC9IfcW8ZrM3qXUdV8W1uXwbvZIbnahKkD3NsmdXNMi12nKgNviLRr/YbI0NSdK3/ryHg29FXbDa9PfPiveaPXHVW6jOhvdqUroX8EEEAAAQQQMJ8AyV/E5TIHEUAAAQQQMJsAyZ/ZrijzQQABBLoVIPlTevW+YcOGESNGBEdZuXLlyJEjQyM+88wz+/btC359/PHHjxw5EqFxsFlGRkZq++eOO+4I9RN5Y2HB2Ve/2BO5jZpHXev/4Jg/VD+/aVPtbW3RIHvP5AV+E3mlKJrGKrSZt7Ws7+jMRs3fEHl7qp7ijMCjUBsrbu/Q+L/Wb44+MinP6xMVrYPkT1FeOkcAAQQQQCDJBUj+ul0msxMBBBBAAAGzCpD8mfXKMi8EEEDgewIkf0ov9devX98x+Rs1alRoxKeffrpj8nf06NEIjUNnBTdiCgMkSep0uoZfvaXfBsKbqhMa1tBxaNXe1tZx0HDbrqw/O2Y/7Pcp/uq4cAV02v/LOYWv6+MNkcHCxJtXBFuq5+BXnerU6uvWE9ctVvuh8npFC4jpZle0EjpHAAEEEEAAAfMJkPx9b3nMFwQQQAABBMwuQPJn9ivM/BBAAIF2AZI/pVfvER7gqc7TPpWeYKz9335b28xYT1SoffHF2sDb2k7dUKj/GLr1eR2zH3ZlfhjDKUo2rbypozdEhibqyHjGueqV0FdtN9pc3rSx2dOyTypaBsmforx0jgACCCCAQJILkPzxhwEEEEAAAQSSSoDkL6kuN5NFAIHkFSD5U3qp7/V677rrrsuXL7vd7pSUlNOnT4dGzM3NHT58uCRJxcXF/fv39/v9ERqHzgpuGDoMcK542bH4551mpNVXj08cPDF3zLoSrQoIjeu7WizYUr1nckN7tN1YvveSxWqvaGjVtoxOo7t3ThNsaZLQ2Gm/Vl//8HXRU9O3K/qzWkPf7FpdF8ZFAAEEEEAAgSgFSP6S928BzBwBBBBAICkFSP6S8rIzaQQQSD4Bkr8ol8SJNMvLy7v77rt79eo1efJkv9+/sP3j9/slSXrvvfd69ep1//33HzlyJDhEp8bhxjV0GKC3t7X9Ze2RIcq/rS3cpQztd2//TJjaX3LpJWn7/aK9z8/eESpPJxu+66WBfPTERp3Us674ssVqv1jTrFw9hr7ZlWOhZwQQQAABBBCQRYDkL/n+BsCMEUAAAQSSWoDkL6kvP5NHAIHkESD5k2XBrH4nhg4DxIbLgbe1HVqivlu3I+a3v63tsMJva+t26L/tlCTHFz91rn3zb3s03WoS3P3GZM3J/9tPVDUtp8PgouiY+6hrw7sddmm5WdvssFjtGYXnlCvC0De7ciz0jAACCCCAAAKyCJD8Jc/an5kigAACCCDQ2NhI8sc/AwQQQCApBEj+ZFkwq9+J0cMAx6Knk+1tbZH/kYi15wJp6NFVkZupdjTraIXFaj9xTS8P1ew4cVfuGGH6QL/H2XGnhtsvL9j98oLdyhVg9JtdORl6RgABBBBAAIHEBUj+kmLZzyQRQAABBBC4LUDyd1uC/yKAAAKmFiD5S3y1rEkPRg8D3IVTdfW2tneWKP62tsj/Ttz75gu2VKm5OnIz1Y7+aeWhoZPzRVFSbcToB/Jd3Bl44OeFwuhPUbRlRuE5i9Ve2+xQaBSj3+wKsdAtAggggAACCMgiQPJn6uU+k0MAAQQQQKCzAMlfZxG+I4AAAqYUIPmTZcGsfidGDwN814+1v61tk/p03Y74zQHF39bW7bihnc6vX3Au/VXoq7YbTo/voQk5EzeValtG2NG9LmHGQFfu6LAN1D1wsabZYrWvK76s0LBGv9kVYqFbBBBAAAEEEJBFgOTPlMt8JoUAAggggEA4AZK/cDLsRwABBEwlQPIny4JZ/U4MHwYk39vaIvwjkZqrAo/63L8gQhs1D+05W22x2vec08sPELvO3bXxj465j/pFsesh9fdIkvT09O3vLClSaGjDYgIUGwAAIABJREFU3+wKudAtAggggAACCMghQPJnquU9k0EAAQQQQKAnAZK/noQ4jgACCJhCgORPjvWyBn2YIAzQ49va5u/S4Fr6/Z4jKwRbqlh3QZPRuw76ycbSgRNyXF5f10M62eM9uVmwpfoqS3RSz4zcU2ljs1udHiXqMcHNrgQLfSKAAAIIIICALAIkf6ZY1jMJBBBAAAEEohUg+YtWinYIIICAoQVI/mRZMKvfiQnCAH2+ra2mSam3tUX4R+Jc84bjy2F+SRcv1RNFaejk/A9XHYpQsOaHJMctwZbmLkzXvJJgAUevNFis9i3HK5WoxwQ3uxIs9IkAAggggAACsgiQ/Bl6OU/xCCCAAAIIxCpA8herGO0RQAABQwqQ/MmyYFa/EzOEAbp8W9vaA0q9rS3cPxLJ2Syk93cXTA7XQOX9pRU3LVZ7dkmFyuPGOpxz9auORU/FepZC7X2i9OinWz5ee0SJ/s1wsyvhQp8IIIAAAgggIIcAyZ8hl/EUjQACCCCAQLwCJH/xynEeAgggYCgBkj851ssa9GGOMEBvb2t7ZkbB21/tV/lyek9nBR5cee2wyuOGG25W3ul+Y7KaBUUeXBlu0Dj2ew4tDTwitf5SHOcqccr49SWDJ+Z6fPK/etAcN7sS5vSJAAIIIIAAAokLkPwZavlOsQgggAACCCQqQPKXqCDnI4AAAoYQIPlLfLWsSQ/mCANuv63tqCaGXQedkXsqdWxWizJva+s6XHCPa/MHjtlD/KJeXqr37MyCEYvVjj/D4UTYL96qFGypnqIvI7RR81BhWZXFai+6UCv7oOa42WVnoUMEEEAAAQQQkEWA5M8Qy3aKRAABBBBAQC4Bkj+5JOkHAQQQ0LUAyZ8sC2b1OzFHGBB4W1t6f/cOm/qA3Y5Y0v62ttxSRd7W1u2Ifq9bmDnIlfNx90dV33uptsVita8pKld95HgGdC75hXPZi/GcqcA5To9vwPicz+zHZe/bHDe77Cx0iAACCCCAAAKyCJD86Xq5TnEIIIAAAgjILUDyJ7co/SGAAAK6FCD5k2XBrH4npgkDnGtecyz8mV+S1DfsOqJPlB77bMufV6v34E3fpd2CLdV7fnvXYjTZs3jnOYvVXnVL0GT0WAd1750r2FKllppYT1So/fvLi5+0bZXk/sdsmptdIXa6RQABBBBAAIFEBEj+dLlMpygEEEAAAQSUEiD5U0qWfhFAAAFdCZD8JbJO1vBc04QBnsPLA29rq7ugIWbHocevPzbok1yXV6Vnb7ryxgnTB/o9jo41aLj98oLdL83fpWEBMQ0t1pwJPPDz6OqYzlKusf1IhcVqP1XZKO8QprnZ5WWhNwQQQAABBBCQRYDkT1fLc4pBAAEEEEBAaQGSP6WF6R8BBBDQhQDJnywLZvU7MU0YIDVXCbZU97756ht2O+KuM4G3te09V93tUZl3iqJj7qOuDe/K3G283dU2OyxW+6IdZ+PtQPXzJMnxxZPOtW+qPnD3A95qc/cbkzUn/3T3h+Pda5qbPV4AzkMAAQQQQAABBQVI/nSxLKcIBBBAAAEE1BIg+VNLmnEQQAABTQVI/hRcRivZtZnCAOfSF5xfv6CkVgx9Oz2+hybkfLKxNIZz4m3qqywJPOrz5OZ4O5D5vG8OXLZY7RdrmmXuV8nu3Ns/E6b2l5wtSg4SQ99vLtr381k7YjghiqZmutmjmC5NEEAAAQQQQEBVAZI/TZfjDI4AAggggIDaAiR/aoszHgIIIKCJAMmfqgtr+QYzUxjg2b8g8La2phvy8STU04erDj32Wb5PVPzVg+4dU4T0/pLjVkLlynfy/ywpenr6dtlfUydfgd305Ks4GEhPT2d3c0yLXav2XbJY7eV1ciaRZrrZtbgmjIkAAggggAACkQRI/jRZhjMoAggggAACWgmQ/Gklz7gIIICAqgIkf5HWwTo+ZqYwQKy7GHhb2+HlOvHOOXbNYrWXXGlQth5Jcnw5zLnmNWVHibr3FqcndWzWjNxTUZ+hj4aizzF7iGvzB/qoxl91S7BY7Yt3npOxHjPd7DKy0BUCCCCAAAIIyCJA8qfq8pvBEEAAAQQQ0FqA5E/rK8D4CCCAgCoCJH+yLJjDdXLz5s0nn3zyJz/5yZNPPtnY2Nix2bVr1x577LF77rnn3nvvnTt3bvDQxIkTf/jDH1raP3l5eR3bd9o2WRjgWDhcbxnY9JyTnczl/SrWng/knUdWyNtt3L2plHfGXV/4E105HwszB/m9rvBNVD3y0vxdLy/YLeOQJrvZZZShKwQQQAABBBBIXIDkT5VlN4MggAACCCCgFwGSP71cCepAAAEEFBUg+Ut8tRyhh48//jg9Pd3v96enp//lL3/p2LKqqqqkpMTv97e0tNx9991lZWV+v3/ixIkzZszo2CzctsnCAHdhuq6ee/nOkqLh05R97qVn37zAM06bq8NdYpX3/2nloaGT80Xln3Eq+7y8FwoFW6rv4k7Ze46vw4zCcxarvabJEd/pXc8y2c3edYLsQQABBBBAAAENBUj+FF1u0zkCCCCAAAJ6EyD509sVoR4EEEBAEQGSP0WX2X369KmqqvL7/VVVVX369Ak31s9//vPt27cnc/Lnu14aeFvb8Q3hiFTev/7gFYvVfq6qSblxnUuedy79lXL9x9Szw+0bMD5n0ubSmM7SS2OvS5gxyJX7vWRdw9ou1TZbrPa1ReVy1UDyJ5ck/SCAAAIIIIBAVwGSP0WW2XSKAAIIIICAXgVI/vR6ZagLAQQQkFWA5K/r6lfGPf/0T/8U6u0HP/hBaLvjxpUrV370ox81NzcHk78777zzgQceePPNNzs9HTR4SkZGRmr754477ujYieG3RdExf6jz23d0MpH6FueDozMXbDujUD3ircrAoz6LvlCo/1i7LTh1w2K1F12ojfVEnbR3bf7AMfsRv+jTQz2SJD07o2DE4v1yFUPyJ5ck/SCAAAIIIIBAVwGSP1mX13SGAAIIIICA3gVI/vR+hagPAQQQkEWA5K/r6je+PU888cR93/9kZmb2mPy1trb269dv06ZNwUFramp8Pp8oimPHjn3zzTcjVGK+MMCd/4kwbYDkaoswazUPvfblnl/OKVRoRM+hJYItVayX7WdhCdY5et3Rh/+a5/GJCfaj1enespzAAz+vHtCqgE7jzso73W9MVpPg7rQ/vq/mu9njc+AsBBBAAAEEEFBCgORPlmU1nSCAAAIIIGAUAZI/o1wp6kQAAQQSEiD5U2L9HOoz8tM+PR7PsGHDZs2aFWof2rhy5cp9990X+tp1w3xhgO/qgcADP8tyuk5Wkz3L9ly0WO3XGhRJIp0rXnZkPKvJvLoO6vGJgyfmjlkXeOukQT+Sq02YNsC9daJO6j9xrdFitduPVMhSj/ludllY6AQBBBBAAAEEZBEg+UtoOc3JCCCAAAIIGE2A5M9oV4x6EUAAgbgESP5kWTCH6+Sjjz5KT0/3+/3p6ekff/xxx2aSJL322mt/+tOfOu4MvhTQ7/fPnj37pZde6nio07YJwwDR55g9xLX5/U4z1epr5c02i9W+dPd52QuQWmoFW6p792zZe46vw6ILNRarvbAs8EJK436c377jmD/UL0l6mIIkST+1bR25TJ7fIJrwZtfDRaIGBBBAAAEEEGgXIPmLaxnNSQgggAACCBhVgOTPqFeOuhFAAIGYBEj+FF3yNzQ0PP744z/5yU8ef/zxmzdv+v3+GzduPPXUU36/f9++fX/3d3/3wAMPWNo/eXl5fr//d7/73f333//AAw8899xzoRSw2wpNGQa4cv8izBjo9zi7nbL6O1+ct/OVz3fLPq7nyMrAoz5rlHqJYKwF/3VT6UMTcpweXbwkL9biQ+29xzcEHvh5ozS0R9uN9KyTaeOyW52exMsw5c2eOAs9IIAAAggggIAsAiR/MS2faYwAAggggIDRBUj+jH4FqR8BBBCISoDkT5YFs/qdmDIM8F3cFXjg5/kC9T27HTGj8JzFaq9uEro9GvdO55rXHF8O08mv03yi9Nhn+R+uOhz3dHRyoiQ0Cun93YWBn9jq4XP0SoPFas85di3xYkx5syfOQg8IIIAAAgggIIsAyV9Uy2YaIYAAAgggYBYBkj+zXEnmgQACCEQUIPmTZcGsfifmDAO8bmHmYFf2R+p7djvi5boWi9W+ct+lbo/GtzMQUNnSTBlQxQci41m6ilRFURo6Of9PKw8lPkFz3uyJu9ADAggggAACCMghQPIXcbnMQQQQQAABBMwmQPJntivKfBBAAIFuBUj+5Fgva9CHWcMAV+b/OmY/7PfJ8IxEWa7KL+cUvv7lXlm6CnbiLV3X/lDK4zL2mUhXtqwTaeOy21zeRDrRybmeo6sCj1GtLtNJPZM2lw4Yn+NwJ/oYVbPe7Dq5TJSBAAIIIIBAkguQ/HW7TGYnAggggAACZhUg+TPrlWVeCCCAwPcESP4MutQ3axjgPbslEIyV79HJdfli+9kHR2fWNTvkqsf5zVuOBU/o5FGfoig9MWXrqOXFcs1O236k1vrA7yl3zdC2jNDoxRdrLVb79pPXQ3vi2zDrzR6fBmchgAACCCCAgLwCJH/fWx7zBQEEEEAAAbMLkPyZ/QozPwQQQKBdgORP3pWzar2ZNgzwOITpA125o1WTjDzQxZpmi9W+tqg8crMoj0rOFmFqf/e2T6Nsr3SzY1cD76LLLpHhXXRKlxpl/85VrzgWDtdJsOr1iUMm5X289kiUxYdrZtqbPdyE2Y8AAggggAACKgqQ/PGHAQQQQAABBJJKgOQvqS43k0UAgeQVIPlTcVkt51AmDgNcm993zH7E79PF8yclSXpuZsGbi/bJcvG8J+2BXzReOyxLb4l3MjX7ZNrY7FanXp6tmviMPEdWBB74WXM28a5k6WH8+mODPsl1eRN64KeJb3ZZkOkEAQQQQAABBBIRIPlL3r8FMHMEEEAAgaQUIPlLysvOpBFAIPkESP4SWSdreK6JwwDvmTxdPfBz3tayvqMzb7a6Er/czm/fccx7zC+KiXeVeA+iKP3UtnXksgOJd6WfHqTWusADP3fP0klJe89VW6z2nWVVidRj4ps9ERbORQABBBBAAAFZBEj+ku9vAMwYAQQQQCCpBUj+kvryM3kEEEgeAZI/WRbM6ndi5jDguwd+WtVX7XbEMzduWaz2b4uvdHs0+p23H/U5KfpTFG1ZWnHTYrVnHa1QdBT1Ow888HPRU+qP2+2IHp/4yKS8vyT2wE8z3+zdqrETAQQQQAABBFQUIPlLnrU/M0UAAQQQQKCxsZHkj38GCCCAQFIIkPypuKyWcyhzhwF6e+Dn09O3j1ic6AM/vSc2Bn7LWHlUzn8HCfQ1rf1Rny0metRnEMNzeHnggZ+15xKwkfPUCRuODZyQ4/TE/8BPc9/sclrTFwIIIIAAAgjELkDylxTLfiaJAAIIIIDAbQGSv9sS/BcBBP5/9u4EKMo7z//4bv23tmprayv+Z2d2djfXYBhNFGwVvI1EMBo1iUkYzzEmxsw/JkYzk6Ctgjp4gEpE45HE6GBi4oGONIKI4Em8D0S8L1CR+2ig4eGm+1/t43RaaJrupo+nn35TVubp5/k9v+P1dE/Vtz/1PI2ArAVI/qyvjiVxhrzDgMYb+yX1wM81yfoHfpZoajty7Wt3TqtZF6jTajvSib3O1Wq1wyNTPomR1aM+RRytpkiI8Ks/Fm0vqw72c/J2oUKpSr2SZ3M/8v6w28zCiQgggAACCCBgFwGSP1mX+ywOAQQQQACBlgIkfy1FeI0AAgjIUoDkzy4Fs/M7kXkY0FAjRPWv2zfH+bAmR7xVUKFQqradzDJ51JKd2ppyIbJPfeoSSxo7oU1mjlqhVKnOy+1RnyJd7daJNd+OcgKjJUM0NjUPWbz/85/OWdLYZBuZf9hNrpmdCCCAAAIIIOAsAZI/WZb5LAoBBBBAAIG2BEj+2pJhPwIIICArAZI/Z9XUdh5H9mFAXdysmujBuqYGO8PZ1J1Wqx2z6tCUr3+26Wz9SY0Zsfq7GPMybO7Bvicuf/Soz8oaSfDad2k6ne7xAz8Lb9i9Z9s6XLQno29YYk29jQ/8lP2H3TZVzkIAAQQQQAABuwiQ/MmqvGcxCCCAAAIItCdA8teeEMcRQAABWQiQ/NmlYHZ+J7IPAxpvJOujsrtHnW9rcsQNqTd6zo0vqBBMHm13Z+32qTXrgyTyqM+mZm3gsuSZ359ud9pu2kBbVSJE+NcfWSmR+Z+5W6xQqpIzc22bj+w/7LaxcBYCCCCAAAII2EWA5E8WZT2LQAABBBBAwFIBkj9LpWiHAAIIuLUAyZ9dCmbndyL/MKChVogaUJcQ4nxbkyNmFWsUStWWtDsmj5rfqRXU+kd9HlpmvpnTjopBVFLGQ6eN6PyBardNqdkwTDpR6ytLkj/betY2B/l/2G1z4SwEEEAAAQQQsIcAyZ9bl/NMHgEEEEAAAWsFSP6sFaM9Aggg4JYCJH/2qJdd0IcnhAF1e78Qvhyga6h1ga+pIYPXHJmw7pipI+3sa0jfJkT4NednttPOWYcX7cnot8D2h086a5odGufx41VzpfJ41SWqS31CE6rrGm1YlSd82G1g4RQEEEAAAQQQsIsAyZ9blvFMGgEEEEAAAVsFSP5sleM8BBBAwK0ESP7sUjA7vxNPCAOa7h4TIvwaryc5n9fkiN8dualQqh6WVZs8amZn7Y+Tar4eLpH7zxqaml8OT5q9/byZCcvgkLamQljepz4lXCJrOZ9dqlCqEtJzbJiPJ3zYbWDhFAQQQAABBBCwiwDJn1uV70wWAQQQQACBjgqQ/HVUkPMRQAABtxAg+bNLwdxWJ2VlZcOGDfP29h42bJharW7R7Pnnn/fx8VEoFIZv9s23Nz7dcIrxTrltNzXWrH65bvd0iazrYVm1QqnadOSWVfPRVuYLEX71adFWneW4xmk3ChRK1ZFr+Y4bQiI91+36qGZNgK65SQrzaW7WDo9M+ehvJ22YjEd82G1w4RQEEEAAAQQQsIcAyZ9blO1MEgEEEEAAAXsJkPzZS5J+EEAAAUkLkPzZo15us4/Zs2dHRkbqdLrIyMg5c+a0aPf888+XlJQY7zTf3rilh4QB9ckLheV9tbWVxmt34fak9cfeXn3Yqgk0nPpW/6jP0myrznJc47k7Lgz6a1J9Y7PjhpBIz41XE4QIv6Z7JyQyn+j9V3vP21taZfXTaz3kwy6Ry8Q0EEAAAQQQ8DQBkj9Jl+tMDgEEEEAAAXsLkPzZW5T+EEAAAUkKkPw5tLbv0qVLfr7+5qr8/PwuXbq0GKt18me+vfHpHhIGND1M1z/w89Iu47W7cHvbySyFUnUzv8LyOdRuerP2b+9Y3t6hLWsbmvovSFyw+6JDR5FI59p6QYjqX7dPKZH53C6oVChVP53IsnY+HvJht5aF9ggggAACCCBgFwGSP0mW6UwKAQQQQAABRwmQ/DlKln4RQAABSQmQ/NmlYG6rk6eeespwqFOnToZtceN3v/tdr169evfuvXHjRnGP+fbGp3tKGKDV1qwfVrttivHaXbhdVlXXe97eL/ddsXAOzUW3hAi/hrObLWzv6GbJmbkKperUnSJHDySR/utUn9WsGqhrrJfIfN5efXjS+mPWTsZTPuzWutAeAQQQQAABBOwhQPInqfKcySCAAAIIIOBoAZI/RwvTPwIIICAJAZI/e9TL+j6CgoK6P/kXHx9vPsnLy8vT6XRFRUU9evRIS0vT6XTm2+t0uo0bN/o9+nvuuefsNXOJ91N/ZIUQ4a+tKpbIPD+JORW07EBTs9aS+TyevEYqSduMLacClyVbOHlLFijxNk13jujvGb15QCLz3Hz0lkKpelBaZdV8SP6s4qIxAggggAACCFglQPInibKcSSCAAAIIIOAsAZI/Z0kzDgIIIOBSAZI/qwpjaxtb+PTORYsWRUVF6XQ6C9vrdDrPCQOai24+um3ub9biO6j9/ksPFUrVaUtum9PfsBgknRsWS6tq9TcsJll6w6KDAJ3abVNjzeohdbs+cuqgbQ+WXy70nBv/9cEbbTcxccRzPuwmFs8uBBBAAAEEEHCwAMmfS8txBkcAAQQQQMDZAiR/zhZnPAQQQMAlAiR/Di2lQ0JCIiMjdTpdZGTk7Nmzjceqrq7WaDQ6na66unrAgAHJyck6nc5Me+NzPSr50+l0+p/K2/xWCwFXvaxtaBqwcF9obHq7E2jKOf/oRwp3t9vSOQ22Hr+rUKpuF1Q6ZziJjFKfukSI7KMV1BKZz3vf/Pz6lwe1WovuGRXnTPInkWvHNBBAAAEEEJClAMmfS8pwBkUAAQQQQMBVAiR/rpJnXAQQQMCpAiR/Di3gS0tLAwMDvb29AwMDy8rKdDpdXl7eyJEjdTpdVlZWj0d/3bp1W7p0qTiN1u3bmp5HhQENZzcLEX7NhdbdKdUWXcf3h8amD1i4r7ahyXxXdUnzhRX9tHXWPdrRfJ8dOTpu7dGxXx3pSA/ueG5zwVX9PaPnvpfI5HeduadQqq4+LLd8Ph71YbechZYIIIAAAgggYBcBkj+nlt8MhgACCCCAgKsFSP5cfQUYHwEEEHCKAMmfXQpm53fiUWGAtrpUiOxTf/BxPup87RYjnrlbrFCq9l962GL/Ey8baoQvB9apPntip+te3CmsVChVP/x813VTcNnINd+9URvzjsuGf3LgSqHhi23nbxVUPLnb3CuP+rCbg+AYAggggAACCDhAgOTPKWU3gyCAAAIIICAVAZI/qVwJ5oEAAgg4VIDkzwHlszO69LQwoG7XRzWrh+iaGp2B294Yzc3aYREHpv/tpJmGjVfihQi/puyfzbRx5qFVSVd7z9tbWlXrzEElMlbD6Y36e0aL70hkPtZOw9M+7Nb60B4BBBBAAAEEOiJA8ufQcpvOEUAAAQQQkJoAyZ/UrgjzQQABBBwiQPLXkTrZhed6WhjQePOA/jfzbh9yobnx0KuTr/aaG19YUWO803i7dtu7NeuCdM3Nxjtdtd3UrA1aduCTmFOumoBrx9VqioQI//ojK1w7DZtH97QPu81QnIgAAggggAACNgiQ/DmkzKZTBBBAAAEEpCpA8ifVK8O8EEAAAbsKkPzZUB5L4RSPCwMa62uiB9f9/WMp4Ot0ugelVQqlauPhmybn01z+UIjwqz+2yuRR5+88ebtQoVQlZ+Y6f2iJjFi7fWrN2kCJBLHWmnjch91aINojgAACCCCAQAcESP7sWl7TGQIIIIAAAlIXIPmT+hVifggggIBdBEj+OlAmu/JUDwwD6g/8VVjeRyuoXeluNPb73/48cmVqc7PWaN/jzfqfv9I/XlL9oPUhl+z5/Kdzg/6aVNvQ5JLRpTBo49W9+oevZqVJYTLWzsEDP+zWEtEeAQQQQAABBGwWIPmzS1lNJwgggAACCLiLAMmfu1wp5okAAgh0SIDkz+Yi2bUnemAY0FxwRYjwazj3vWvlDaMnpD9QKFVn7hYb9jze0GprNrxa++Oklvtd9FpdXe8/PyFib6aLxpfGsA21j+4Z/UQas7FuFh74YbcOiNYIIIAAAggg0AEBkr8OldOcjAACCCCAgLsJkPy52xVjvggggIBNAiR/HSiTXXmqZ4YBtZverPnuTZ3WxG12zr8YtQ1NAxftU+640GLopvun9T9JeGl3i/2uerkl7Y5CqbpTWOmqCUhk3PqUxUJkH21ViUTmY/k0PPPDbrkPLRFAAAEEEECgIwIkfzaV0ZyEAAIIIICAuwqQ/LnrlWPeCCCAgFUCJH8dqZNdeK5nhgEN57fqn9mYe9GF8sZDh8dl9AlN0NQ2GO+s2/uFENVfWy8Y73TVtlarff3Lg5PWH3PVBKQzbnPxbf09o6e+kc6ULJyJZ37YLcShGQIIIIAAAgh0UIDkz6rymcYIIIAAAgi4uwDJn7tfQeaPAAIIWCRA8tfBUtlVp3tmGKCt1Qgr+9clhLiKvcW4Vx6qFUrVjlPZhv1aQS2s6FuXNN+wx7Ub57NLFUrVnnP3XTsNiYxe+8P4mq+HS+SeUctNPPPDbrkPLRFAAAEEEECgIwIkfxaVzTRCAAEEEEBALgIkf3K5kqwDAQQQMCtA8teROtmF53psGFC3b66wop+2psKF+IahtVrt26sP/2HNEe0/HkDacHqjEOHXXHDN0Ma1G3N3XBiwcJ9Q3+jaaUhk9MbMv+vvGb13UiLzsXAaHvtht9CHZggggAACCCDQEQGSP7PlMgcRQAABBBCQmwDJn9yuKOtBAAEETAqQ/HWkTnbhuR4bBjTnZ+qf2Xg2xoX4xkPvOJWtUKou3i/T72xurvl6eO33Y40buHC7UmjoE5oQHpfhwjlIa+iGmppVA+viZklrVu3NxmM/7O3BcBwBBBBAAAEE7CBA8meyTGYnAggggAACchUg+ZPrlWVdCCCAwBMCJH92KJdd0YUnhwG1f3u7ZuNoiTyzsbquccDCfXO2n9fpdE1ZaUKEX2PmHle8I0yM+ePxuwql6lpuuYljnrqrPnmhsLyPtvpRUusmCJ78YXeTS8Q0EUAAAQQQcGMBkr8nymNeIIAAAgggIHcBkj+5X2HWhwACCDwSIPlz0zLdk8OAhvRt+mc25pyTyLVbFp/pN39viaa2btdHNdGDdQ21UphYc7N2dNTBCeuOSWEy0plDc+EN/T2jJzdIZ0rtzsSTP+zt4tAAAQQQQAABBDooQPLHFwMIIIAAAgh4lADJn0ddbhaLAAKeK0Dy18FS2VWne3IYoK2rFr4cUKeSyjMbs4o1CqXqh/3HhQj/+kPLXPWWaDFu2s0ChVKVeDGnxX5e1v70x5q1Q3VNDe5C4ckfdne5RswTAQQQQAAB9xUg+fPc7wJYOQIIIICARwqQ/HnkZWfRCCDgeQIkf25apXt4GFCfEi5E9tFW5kvk8n246cTGxR9VL/NrLrsvkSn9afPJoUuT6xubJTIf6Uyj8WaK/qFMUrsIAAAgAElEQVSsVxOkMyXzM/HwD7t5HI4igAACCCCAQAcFSP487zsAVowAAggg4NECJH8efflZPAIIeI4AyV8HS2VXne7hYUCz+oH+BrvDka7ybzHu4cx7D5b0ffjdxBb7XfXybpH+NsRvDt5w1QQkPW5zU82GV2u/HyvpSRpNzsM/7EYSbCKAAAIIIICA/QVI/jyn9melCCCAAAIIqNVqkj/eBggggIBHCJD82b96dkqPhAF1u6fXrBqorRec4t3OIHUX9D89uHStVH49bnHcJf/QhLKqunbm7amHG85u1v9UZN4ltwDgw+4Wl4lJIoAAAggg4KYCJH8eUfazSAQQQAABBP4hQPL3Dwn+FwEEEJC1AMmfQ0v0srKyYcOGeXt7Dxs2TK1WG4918+ZNxT/+/uM//mP16tU6nW7RokX/+7//K+5OSkoybt9imzCgKeecEOHXcO77FjIueNncXPPtyIerRyiUqss5T1xlF0xGp6usaei3IHF+bLpLRneLQbW1GiFqQF38n91itnzY3eIyMUkEEEAAAQTcVIDkT9blPotDAAEEEECgpQDJX0sRXiOAAAKyFCD5c2iJPnv27MhI/RMpIyMj58yZY3Kspqam3/72t/fv638fbtGiRVFRUSabtdhJGKDTamtj3qn5eriu2cU/Zdd466AQ4Vd18e8DF+37bOvZFlfK+S9jjt1SKFXX88qdP7QbjVh/YJH+pyI1hdKfMx926V8jZogAAggggID7CpD8ybLMZ1EIIIAAAgi0JUDy15YM+xFAAAFZCZD8ObRK79KlS35+vk6ny8/P79Kli8mxUlJSBg4cKB4i+TNJ1NbOxivxQoRf463Utho4Z3/t1ok1awN1TQ2rk6/2nBufXaxxzrgmR6ltaBq6NHnqt8dNHmWnQaC57J7+pyIPLTPskewGyZ9kLw0TQwABBBBAQAYCJH+yKu9ZDAIIIIAAAu0JkPy1J8RxBBBAQBYCJH8OLdefeuopQ/+dOnUybBtvTJ06dd26deKeRYsWPf/8876+vlOnTm3xdFCxwcaNG/0e/T333HPGnXjodlNDzdrA2u/H6bRaVwk05WXoHzp6eqNOpyvR1PqHJizYfdFVk9HpdDtOZSuUqtN3ilw4B3cZuk41S1jZXyu4/gGt5sVI/sz7cBQBBBBAAAEEOiJA8ieLsp5FIIAAAgggYKkAyZ+lUrRDAAEE3FqA5K8jdbLxuUFBQd2f/IuPj283+auvr//P//zPwsLHjxwsLCxsampqbm6eP3/+1KlTjftvsU0YIII0nN0iRPg1ZbvsFre6PTOELwdoax/f5xcel+E/P6G4sqbF9XLOy4am5uGRKZPWH9O6Lgp1zkrtMkpz0U0hwq/+6Jd26c1xnfBhd5wtPSOAAAIIIIAAyZ9bl/NMHgEEEEAAAWsFSP6sFaM9Aggg4JYCJH8OrfbbfdpnfHz8q6++2noO9+7d6969e+v9hj2EAY8pGmprvnqldutEl9z211x4Qx8dHV5uuC45pdW95sZ/mXTFsMeZG3Hn7iuUqmM39A+Y5c8Sgbrd04UvB2prKy1p7Ko2fNhdJc+4CCCAAAIIeIIAyZ9blvFMGgEEEEAAAVsFSP5sleM8BBBAwK0ESP4cWs+HhIRERkbqdLrIyMjZs2e3Hmv8+PExMTGG/eKPAup0uujo6PHjxxv2t94gDDCYNJyN0d/2d++EYY/TNh7lRgNaPC7yi23n+y9ILKuqc9o0xIGamrWvRx0MXnOEG/4sl2/Oz9Q/rPX4V5af4vyWfNidb86ICCCAAAIIeI4AyZ9ble9MFgEEEEAAgY4KkPx1VJDzEUAAAbcQIPlzaFVfWloaGBjo7e0dGBhYVlam0+ny8vJGjhwpDioIwq9+9auKigrDHCZPnuzj4+Pr6/vGG28YUkDDUeMNwoBfNBpqa9YE6G/7c+6fGBrVH4tuMezdIk2vufGRey+32O/ol0kZDxVKVcrlXEcPJLP+a3d8UBM9WFtXLdl18WGX7KVhYggggAACCMhAgOTPLcp2JokAAggggIC9BEj+7CVJPwgggICkBUj+3LRcJwwwvnANZ//26La/k8Y7Hb2tT4xWmX5QZNiudP/5CXnlgqPnYOi/oan59aiDY1Ydam7WGnayYYlA08N0/SNbj6+1pLFL2vBhdwk7gyKAAAIIIOAhAiR/ki7XmRwCCCCAAAL2FiD5s7co/SGAAAKSFCD5c9OSnjDgiQvXUKO/7e+H8U77tT/zcVFeueA/PyFsV/oTk3Tki+0nsxRK1ZFr/MKfLcq1sX8SogZoq0psOdnx5/Bhd7wxIyCAAAIIIOC5AiR/kizTmRQCCCCAAAKOEiD5c5Qs/SKAAAKSEiD5c9MqnzCgxYVruPCjEOHXeC2xxX6HvNRqa3+abP4RkcsTLveaG3+3SOOQCTzZaVVtQ8Di/e9/+zO/8PckjKWvmkvuChH+dUmhlp7QwXZa6+7L5MPeQW9ORwABBBBAAAEzAiR/kirPmQwCCCCAAAKOFiD5c7Qw/SOAAAKSECD5M1MGS/kQYUDLq9PcVPPdGzXrgnQNNS0P2ft14439QoRfw9m/mem4rKqu/4LEz7aeNdPGXodWJ19VKFVXH5bbq0MP7Kduf5gQ4d9cfNvRa9dqCms3v9WUm2H5QHzYLbeiJQIIIIAAAghYK0DyJ4mynEkggAACCCDgLAGSP2dJMw4CCCDgUgGSP2trY4m0JwxofSGa7p3UB3LHv2p9yI57tPVCzbqgmo2v65oazXe7IfWGQqk6dafIfLMOHs0vF/qEJszZfr6D/Xj46drqUuHLAbU7pznaoS5ulrC8b3NptuUD8WG33IqWCCCAAAIIIGCtAMmfS8txBkcAAQQQQMDZAiR/zhZnPAQQQMAlAiR/1tbGEmlPGGDyQtTtni6s7KetdODP3dUfWyVE+DXdP2VyAsY7axuaRq5MHR11sLahyXi/fbfnbD/vH5qQq662b7ce2FvDyQ36K5uV5ri1N2WlCRF+9ceirRqCD7tVXDRGAAEEEEAAAasESP5cUoYzKAIIIIAAAq4SIPlzlTzjIoAAAk4VIPmzqjCWTmPCAJPXornsvrC8T53qM5NHO77zUf996+JmWdjVyduFCqVqfep1C9tb2yztRoFCqVp74Jq1J9LehEBDbc2GYTUbXtXWCyaOdnxXQ23N18Nrvh6ua6i1qjM+7FZx0RgBBBBAAAEErBIg+XNq+c1gCCCAAAIIuFqA5M/VV4DxEUAAAacIkPxZVRhLpzFhQFvXov5olBDh13grta0Gtu/Xamt3ThNW9rfqnsKQbef95ydkF2tsH7eNMzW1DcMiDrwVfaiu0YH3FLYxuDx3iw+MrU8Jd8Ty6tOibbunkA+7Iy4HfSKAAAIIIICAKEDy55Sym0EQQAABBBCQigDJn1SuBPNAAAEEHCpA8uemNT9hQJsXrrG+5rs3a1a/rK0ubbONTQca0rfpf0fw9Earzi7W1AxctO+Djce1Wq1VJ7bbeOHfM3rNjc/MUbfbkgaWC9TvD9PncznnLD/FkpbNJXeF5X3r4mZa0rhFGz7sLUB4iQACCCCAAAJ2FCD5c2i5TecIIIAAAghITYDkT2pXhPkggAACDhEg+bNj2ezMrggDzGg3F1zTP/Nz93Sd/cI2fXKzsl/tT5N1zc1mhjZ5aOfpbIVSFXPslsmjtu08fadIoVR9ue+KbadzVlsC2rrqmnVBNd+M0DXUtNXG6v0NNfo0OnqwVlNo9bk6HR92G9A4BQEEEEAAAQQsFCD5c0iZTacIIIAAAghIVYDkT6pXhnkhgAACdhUg+bOwJJZaM8IA81ek4eQG/TM/M/eYb2bp0cb62s1j9MlNZb6lpxi102q1n20923ve3vR79rkNsURTOyziwOiog7UNPOfTCNpOm01ZaUKEX/3+MDv1p6vbN0//brx92LYO+bDb5sZZCCCAAAIIIGCJAMmfXctrOkMAAQQQQEDqAiR/Ur9CzA8BBBCwiwDJnyX1sATbEAa0c1Gam2q/HydEDWguvN5OSwsO1x9cqk9ubh6woK3pJprahpErU4OWHSirqjPdwuK99Y3Nkzek9Q1LuJZbbvFJNLROoD51if7Jrhd+su40U60br8Trc8RDEaYOWrSPD7tFTDRCAAEEEEAAAZsESP7sUlbTCQIIIIAAAu4iQPLnLleKeSKAAAIdEiD5s6lAdv1JhAHtXgNtRV7NV6/UrB2qrSxot7GZBg0XtwsRfnVJ8820seTQtdxy/9CEP20+2dhk9fNCDf1rtdqFf7+oUKqSMh4adrJhf4Hmptrt7wuRfZrun+5I581Ft4So/rXfj9M1NdjcDx92m+k4EQEEEEAAAQTaFSD561A5zckIIIAAAgi4mwDJn7tdMeaLAAII2CRA8tduMSzNBoQBllyX5oIr+txl05vaumpL2rdu03gjWYjwr932nq6xvvVRa/fsOnNPoVQpd1xoatZae67YftvJLIVStTr5qm2nc5blAtqaippvXquJHtysfmD5WcYtm0uza9YE1Kweoq3INd5v7TYfdmvFaI8AAggggAAClguQ/NlURnMSAggggAAC7ipA8ueuV455I4AAAlYJkPxZXhVLqiVhgIWXo/H2YX10t32qrqHGwlMMzZrunxaW962NCdbWC4adHdz49tANhVI1Pza92frw78fjdxVK1Scxp2w4t4PT9szTm0uyalYNrFkf1FySZa1As/pBzdqh+uCw6Ka157Zoz4e9BQgvEUAAAQQQQMCOAiR/VpXPNEYAAQQQQMDdBUj+3P0KMn8EEEDAIgGSPzuWzc7sijDAcu2G9G1ChF9tzDtaTZHlZzXePCBEDaj5dqRWUFt+liUt16deVyhVYbsuWn7nn1arXZeiP+vT70/XNjRZMgpt7CLQnJ9ZE/1yTfTgprwMyztsLrtfsz6oZtXA5gI73J3Jh91yeVoigAACCCCAgLUCJH8Wlc00QgABBBBAQC4CJH9yuZKsAwEEEDArQPJnbW0skfaEAVZdCP1DO1f2q1kbaFES09RYfyhCHxb+7W1tZb5VA1nSWKvVfnXgmkKp+uOGtJzS9h9DWl3XuPDvGQqlKjQ2vSO/EWjJ3GjTWkD/0M71QcLK/o03D7Q+2npP42WV8OUA4cuBTXmXWh+1YQ8fdhvQOAUBBBBAAAEELBQg+TNbLnMQAQQQQAABuQmQ/MntirIeBBBAwKQAyZ+FJbFtzXbt2tWtW7d//ud/Pn/+fOsekpOTu3Tp8sILL0RGRopHy8rKhg0b5u3tPWzYMLXa3K1mhAGtPc3v0d+89dUrwoq+9YeWmbmNrykvo/bHSUKEX92+ubqGWvN9duRo4sWcgYv29V+QuOfs/bae3qnVapMzc4dFHFAoVauSrmq1Nv46YEfmybk6nU6rKazd9KY+DN45rbk0uy0TraCui/+zvtn3Y23+dcDWnfNhb23CHgQQQAABBBCwlwDJn8kymZ0IIIAAAgjIVYDkT65XlnUhgAACTwiQ/NmrZjbZz/Xr12/evBkQENA6+WtqaurcuXNWVlZ9fX2PHj2uXbum0+lmz54tpoCRkZFz5swx2ae4kzDADE5bh7SVBXWqz4QIP+HLAfVHv2y6f1pbV6Vv3NysrchrvHmgdutE8Whjxs62OrHj/rxy4f1vf1YoVcMjU9YeuHa/pEqMALVabVaxZuvxu1O+1h8NXnPk4v0yO45LV7YINNY3nPpGiOovLO9Tt0/ZeH3fL/lxQ21T9s91cTOF5X2ECP/6tNW6pkZbhmjjHD7sbcCwGwEEEEAAAQTsIEDy90R5zAsEEEAAAQTkLkDyJ/crzPoQQACBRwIkf3Yol9vrwmTyd+rUqeHDh4unRjz60+l0Xbp0yc/XP14yPz+/S5cuZjomDDCDY/5Qc+H12tj/p0/4Hv2rWTv0UWCjf1mzNrDh9EZtrcZ8D3Y82tysTcp4+OGmEz3nxiuUKoVS1W9B4qC/Jonbo6MO/nQiy/KfA7TjxOjKpIA+PE4IEVb2f/zmWf2ysLzv4+1VA+sPLGouumnyxI7s5MPeET3ORQABBBBAAAHzAiR/fDGAAAIIIICARwmQ/HnU5WaxCCDguQIkf+YrYbscNZn87d69e9q0aWL/W7dunTFjhk6ne+qppwwjdurUybBt2Ni4caPfo7/nnnvOsJMNGwS0mqLG24fqf15TF//n+oPLGs5vbcpK0zU12NCVXU4pqBB+OpG1NuX68oTLi/Zk7DiV/bCs/Z8AtMvQdGK1QFNDU865+rToun3K+kPLGk6sa7yW6Lhnw5L8WX2BOAEBBBBAAAEELBYg+fPc7wJYOQIIIICARwqQ/HnkZWfRCCDgeQIkfxYXxe00DAoK6v7kX3x8vHiOyeRv165dxsnfp59+aknyZ5gEYYCBgg0E5C3Ah13e15fVIYAAAggg4FoBkj/P+w6AFSOAAAIIeLQAyZ9HX34WjwACniNA8ueESttk8sfTPp0gzxAIyECA5E8GF5ElIIAAAgggIFkBkj/Pqf1ZKQIIIIAAAmq1muSPtwECCCDgEQIkf04owk0mf42NjV5eXtnZ2fX19T169Lh69apOpwsJCYmMjNTpdJGRkbNnzzYzN8IAMzgcQkBOAnzY5XQ1WQsCCCCAAAJSEyD584iyn0UigAACCCDwDwGSv39I8L8IIICArAVI/hxae8fFxT399NP/+q//+l//9V/Dhw/X6XR5eXkjR44UB01KSvr973/fuXPnpUuXintKS0sDAwO9vb0DAwPLysrMzI0wwAwOhxCQkwAfdjldTdaCAAIIIICA1ARI/mRd7rM4BBBAAAEEWgqQ/LUU4TUCCCAgSwGSP6nV3hbOhzDAQiiaIeDuAnzY3f0KMn8EEEAAAQSkLEDyJ8syn0UhgAACCCDQlgDJX1sy7EcAAQRkJUDyJ+U63MzcCAPM4HAIATkJ8GGX09VkLQgggAACCEhNgORPVuU9i0EAAQQQQKA9AZK/9oQ4jgACCMhCgORParW3hfMhDLAQimYIuLsAH3Z3v4LMHwEEEEAAASkLkPzJoqxnEQgggAACCFgqQPJnqRTtEEAAAbcWIPmTch1uZm6EAWZwOISAnAT4sMvparIWBBBAAAEEpCZA8ufW5TyTRwABBBBAwFoBkj9rxWiPAAIIuKUAyZ/Uam8L50MYYCEUzRBwdwE+7O5+BZk/AggggAACUhYg+XPLMp5JI4AAAgggYKsAyZ+tcpyHAAIIuJUAyZ+U63Azc/v1r3/tZ/Hf888/b3FbCTVk2s68GGhLVvvXv/61mf8r4BACCCCAAAIIINARAZI/tyrfmSwCCCCAAAIdFSD566gg5yOAAAJuIUDy15E62V3OddN7hpi2M99gaKPtTAHGQgABBBBAAAGJCJD8uUXZziQRQAABBBCwlwDJn70k6QcBBBCQtADJn0RKbodOg1DHobwtOke7BYhDX6LtUF46RwABBBBAAAHZC5D8SbpcZ3IIIIAAAgjYW4Dkz96i9IcAAghIUoDkT/bFvE6nIx1x5lVGG+12Bdz0TdLuumiAAAIIIIAAAm4nQPInyTKdSSGAAAIIIOAoAZI/R8nSLwIIICApAZI/tyvObZjwxo0bbTjL5acwbWdeArTRdqYAYyGAAAIIIICARARI/iRVnjMZBBBAAAEEHC1A8udoYfpHAAEEJCFA8ieRkptpIIAAAggggAACCCCAAAJOFiD5k0RZziQQQAABBBBwlgDJn7OkGQcBBBBwqQDJn5NLa4ZDAAEEEEAAAQQQQAABBCQiQPLn0nKcwRFAAAEEEHC2AMmfs8UZDwEEEHCJAMmfREpupoEAAggggAACCCCAAAIIOFmA5M8lZTiDIoAAAggg4CoBkj9XyTMuAggg4FQBkj8nl9bOHy45OblLly4vvPBCZGSk80e3bcScnJxXXnnlxRdf7Nat25o1a2zrxCVnNTU19ezZc/To0S4Z3bZBy8vLg4ODu3bt+uKLL546dcq2Tpx/VnR0dLdu3bp37z5hwoTa2lrnT8DyEadOnfqb3/yme/fu4illZWXDhg3z9vYeNmyYWq22vB9aIoAAAggggAACdhcg+XNq+c1gCCCAAAIIuFqA5M/VV4DxEUAAAacIkPzZvXiWVIdNTU2dO3fOysqqr6/v0aPHtWvXJDW9tiaTn5+fnp6u0+k0Gs3vf/97d5m2TqdbtWrVxIkT3Sv5mzJlyqZNm3Q6XX19fXl5eVsXRVL7c3Nzf/e739XU1Oh0urFjx27ZskVS02sxmbS0tPT0dEPyN3v2bDGGj4yMnDNnTovGvEQAAQQQQAABBJwpQPLnlLKbQRBAAAEEEJCKAMmfVK4E80AAAQQcKkDy58y62vljnTp1avjw4eK4EY/+nD+HDo745ptvpqamdrAT55z+8OHDwMDAw4cPu1HyV1lZ+bvf/U6r1TqHyF6j5ObmPvPMM2VlZY2NjaNHj05JSbFXzw7q5969e4bkr0uXLvn5+TqdLj8/v0uXLg4akW4RQAABBBBAAAFLBEj+HFpu0zkCCCCAAAJSEyD5k9oVYT4IIICAQwRI/iyph923ze7du6dNmybOf+vWrTNmzHCvtdy7d+/ZZ5+trKx0i2kHBwdfuHDh6NGjbpT8ZWRk9OnT57333uvZs+e0adOqq6vdglqn061Zs+bf//3ff/3rX0+aNEn6czZO/p566inDhDt16mTYZgMBBBBAAAEEEHC+AMmfQ8psOkUAAQQQQECqAiR/Ur0yzAsBBBCwqwDJn/Ora2eOuGvXLuPk79NPP3Xm6B0cq6qqqnfv3nv27OlgP845PTEx8eOPP9bpdO6V/J0/f/7//J//c+bMGZ1ON2vWrLCwMOdwdXAUtVo9dOjQ4uLihoaGMWPG/Pjjjx3s0NGnk/w5Wpj+EUAAAQQQQMA2AZI/u5bXdIYAAggggIDUBUj+pH6FmB8CCCBgFwGSP9sqZHc5y32f9tnQ0DB8+PBVq1a5C/XcuXOffvrp559//re//e2//du//fGPf3SLmRcUFDz//PPiVH/++edRo0a5xbR37dr1wQcfiFP94YcfxMxVyjM3Tv542qeUrxRzQwABBBBAwNMESP7sUlbTCQIIIIAAAu4iQPLnLleKeSKAAAIdEiD5k3dt39jY6OXllZ2dXV9f36NHj6tXr7rFerVa7bvvvvvZZ5+5xWxbTNK97vnT6XSDBw++efOmTqdbtGhRSEhIi+VI8+WZM2e6desmCIJWq50yZcratWulOU/DrIyTv5CQkMjISJ1OFxkZOXv2bEMbNhBAAAEEEEAAAecLkPx1qJzmZAQQQAABBNxNgOTP3a4Y80UAAQRsEiD5c3517eQRk5KSfv/733fu3Hnp0qVOHtrm4Y4fP/5P//RPvr6+ikd/SUlJNnfl/BPdLvnLyMjw8/Pz9fUdM2aMWq12vphtIy5cuLBr167du3efPHlyXV2dbZ0456wJEyb893//97/8y788/fTTmzdvLi0tDQwM9Pb2DgwMLCsrc84cGAUBBBBAAAEEEDApQPJnUxnNSQgggAACCLirAMmfu1455o0AAghYJUDyZ7IAZicCCCCAAAIIIIAAAgggIHsBkj+rymcaI4AAAggg4O4CJH/ufgWZPwIIIGCRAMmf7It5FogAAggggAACCCCAAAIImBQg+bOobKYRAggggAACchEg+ZPLlWQdCCCAgFkBkj+TBTA7EUAAAQQQQAABBBBAAAHZC5D8mS2XOYgAAggggIDcBEj+5HZFWQ8CCCBgUoDkT/bFPAtEAAEEEEAAAQQQQAABBEwKkPyZLJPZiQACCCCAgFwFSP7kemVZFwIIIPCEAMmfyQKYnQgggAACCCCAAAIIIICA7AVI/p4oj3mBAAIIIICA3AVI/uR+hVkfAggg8EiA5E/2xTwLRAABBBBAAAEEEEAAAQRMCpD88cUAAggggAACHiVA8udRl5vFIoCA5wqQ/JksgNmJAAIIIIAAAggggAACCMhegOTPc78LYOUIIIAAAh4pQPLnkZedRSOAgOcJkPzJvphngQgggAACCCCAAAIIIICASQGSP8/7DoAVI4AAAgh4tADJn0dffhaPAAKeI0DyZ7IAZicCCCCAAAIIIIAAAgggIHsBkj/Pqf1ZKQIIIIAAAmq1muSPtwECCCDgEQIkf7Iv5lkgAggggAACCCCAAAIIIGBSgOTPI8p+FokAAggggMA/BEj+/iHB/yKAAAKyFiD5M1kAsxMBBBBAAAEEEEAAAQQQkL0AyZ+sy30WhwACCCCAQEsBkr+WIrxGAAEEZClA8if7Yp4FIoAAAggggAACCCCAAAImBUj+ZFnmsygEEEAAAQTaEiD5a0uG/QgggICsBEj+TBbA7EQAAQQQQAABBBBAAAEEZC9A8ier8p7FIIAAAggg0J4AyV97QhxHAAEEZCFA8if7Yp4FIoAAAggggAACCCCAAAImBUj+ZFHWswgEEEAAAQQsFSD5s1SKdggggIBbC5D8mSyA2YkAAggggAACCCCAAAIIyF6A5M+ty3kmjwACCCCAgLUCJH/WitEeAQQQcEsBkj/ZF/MsEAEEEEAAAQQQQAABBBAwKUDy55ZlPJNGAAEEEEDAVgGSP1vlOA8BBBBwKwGSP5MFMDsRQAABBBBAAAEEEEAAAdkLkPy5VfnOZBFAAAEEEOioAMlfRwU5HwEEEHALAZI/2RfzLBABBBBAAAEEEEAAAQQQMClA8ucWZTuTRAABBBBAwF4CJH/2kqQfBBBAQNICJH8mC2B2IoAAAggggAACCCCAAAKyFyD5k3S5zuQQQAABBBCwtwDJn71F6Q8BBBCQpADJn+yLeRaIAAIIIIAAAggggAACCJgUIPmTZJnOpBBAAAEEEHCUAMmfo2TpFwEEEJCUAMmfyQKYnQgggAACCCCAAAIIIICA7AVI/iRVnjMZBBBAAAEEHC1A8udoYfpHAAEEJCFA8if7Yp4FIoAAAggggJJNB7QAACAASURBVAACCCCAAAImBUj+JFGWMwkEEEAAAQScJUDy5yxpxkEAAQRcKkDyZ7IANrPzPn8IIIAAAggggAACCCCAgFQFzNQyrQ+R/Lm0HGdwBBBAAAEEnC1A8udsccZDAAEEXCJA8te6+jW/5/79+wJ/CCCAAAIIIIAAAggggID0BO7fv2++nGlxlOTPJWU4gyKAAAIIIOAqAZI/V8kzLgIIIOBUAZK/FqVvuy9J/qT3/QYzQgABBBBAAAEEEEAAAb0AyZ9Ty2kGQwABBBBAwN0ESP7c7YoxXwQQQMAmAZK/dqO+Fg1I/vhOBQEEEEAAAQQQQAABBKQpQPJnU1nMSQgggAACCHiKAMmfp1xp1okAAh4uQPLXIthr9yXJnzS/42BWCCCAAAIIIIAAAgggQPLn4QU+y0cAAQQQQMC8AMmfeR+OIoAAAjIRIPlrN+pr0YDkj+9TEEAAAQQQQAABBBBAQJoCJH8yKdRZBgIIIIAAAo4RIPlzjCu9IoAAAhITIPlrEey1+5LkT5rfcTArBBBAAAEEEEAAAQQQIPmTWMHNdBBAAAEEEJCWAMmftK4Hs0EAAQQcJEDy127U16IByR/fpyCAAAIIIIAAAggggIA0BUj+HFQ40y0CCCCAAALyECD5k8d1ZBUIIIBAOwIkfy2CvXZfkvxJ8zsOZ86qsqoyvzSvrKLUmYMyFgIIIIAAAggggAAC7QqQ/LVTAHMYAQQQQAABzxYg+fPs68/qEUDAYwRkk/zl5+cnJCSkpKTk5eW1m97dunUrNTU1Pj6+urq63cYtGrSV/G08vC4wsk/PBZ1fixrUbkEu8QaHDx/29/d3ziSHKJN+PHzLMFaxurLT+G13c8sMe6zd6DkzvtvHcZ3GbysorbT2XAvbH7mSqgjzWqIKtbA9zRBAAAEEEEAAAQQQcI4AyZ/HlPIsFAEEEEAAAVsESP5sUeMcBBBAwO0E5JT8HTx4sEVKZ+Zlc3OzHZO/4vKiXgteeHXFgNhTP+5LVzmhql+7dq2X0d+YMWPEQceNGyfu9vX1HTt27IkTJ9qdTHBw8NatW42buTD5q9RUr0+4UqLWGM/H2u27uWXyS/56L/S2MFQeNGjQli1bRLS8vDwvL69z5869//77Ru+Xx5tLly4V91+8eFFsP2jQIC8vL41G79+/f39DP9ZeAtojgAACCCCAAAIIuESA5M/tSnImjAACCCCAgDMFSP6cqc1YCCCAgMsESP7MpIMmD5m85+96zlVFmNfMrdOcVt5XVVWVl5dHRUWNHj26vLy8oqJCHHrcuHFLlizRaDS5ublKpdLX17ekpMT8rCSV/JmfqoVHHZ38WTgN+zbrYPJXWVlZ/uhv0qRJoaGh4rZGo3n//fcDAwPDw8MFQUhLSwsKCiL5s++FozcEEEAAAQQQQMCZAiR/LiutGRgBBBBAAAF3ECD5c4erxBwRQACBDguQ/LWI965evXrs2LEWO41ftk7+hq3orwjzMvwz3Ji17cQWRZjXoj1zJn/ztv+irgERfqUV+hDu3J3T7377zoDFPm+sHvpD2ibxi4DeC71n/DA1IMIvbHfIh5snDV6qSM5IbPc7gujo6Ndff9242bhx45YuXSruuXHjhpeX1/nz57///vsRI0YYmu3atWvIkCGCIISGhgYEBLz44ot+fn4Bj/7KyvSP2RTv+duwYUOvXr38/f137twpnltVVbVixYqBAwf26tVr2rRpBorg4ODw8PBJkyYFBARMmjSpsLDQMJbJjQPn7/f9S8Iz78XO+PrkoNn7DE/7HLkoRTEzvvXTPrcdud37s73Pvh/70vQ9X+7JFPtUxpx9/a+pwcsOvTJ3/4gFB65kFxvGMpn8/e3A9X6fJzzz3k7fGao5MWfLK6sEQdi4/9qAL35x/unwLcXMeEM/rTceFucYLrThaZ+nbx1XhHmFbJ8REOG3JnnFqFVDRq0acjv3Zml5iSLM6601w2Zv/3TQkh5j1426dO/xrXUm3wOCIJh8z4xf/7phUHHD/HvD5D1/hrVMnjx54cKFhpfvv//+smXLhg4dWl1dHRISsnr1apI/Aw4bCCCAAAIIIICA2wmQ/HW4RKYDBBBAAAEE5CxA8ifnq8vaEEAAAYMAyZ9xqqfT6S5cuJCYmNhip/FLQ9xl+BZgf0bCxsNrFWFe49e/Hncu1pDKiClOzwWdw+PmxZ76cdEeZWlFyf3C7P6Luw9eqli9f/mEDW8owrx2ntI/abP3Qu+x60Z+se1j/Q/IxYcOW9F/+pYphiHa2jCT/FVXV69YseLFF18sLCwsLi5+6aWX0tPTxX4mT54cHR1t6NPkPX/e3t7R0dFqtXrr1q0+Pj7l5eWCIMTExAwePPjWrVtqtXrmzJkTJ04UOwkODh41alRpaWlVVdXYsWO/+uorQ+etN/KKK555b2dMyo1KTfUaVWan8dsMyZ8gCK1/56+0XPObSTuSz90XBCG/pOLopRyxT2XM2d9O3nHtnj7wW59wZWDILwGeyeTv+4M3T17NrdRUZ+eV9f1LQkSsPoQrKtP8z7s7z93IF/t8a8nBZTsfh3OtZy4IQnlledy52JWJi41/509M/mbv+PSdr0b0XND5m0NrFGFe3x1ZLyZ/ijCvxar5m49u6LXghTGrgwRBaOs9YEj+WrxnDl9JiTsX22vBCwHLesedi407F3u/MNvk9MSd1iZ/0dHRM2fOTElJGTJkyIULF0j+zNhyCAEEEEAAAQQQkLgAyZ+h1GUDAQQQQAABBFoLkPy1NmEPAgggIEMBkj/jVM+S7dbJnyAIVx9ktn7ap5j8he7+wvjbATEj3HZC/zNsOcUPei7oPH69/qa93gu9lyeGJ1yIU4R5Xb6fMeOHqWPXjTI+0eS2yeSve/fu/v7+L730UkBAQGLi4zxs1qxZ4p1eOTk5Xbp0uXv3rqFDk8lf165dxR97Ky8v9/LyunnzpiAI48aNM0SG165d8/LyKigoEAQhODh43bp1YoeRkZGzZs0ydN56Y/uRWy9N3yPur64WvKbtNp/8lag1/z1559q9lwtKHj/RVDxXGXN2zOKD4nZpuabT+G2G2/5MJn/GM1m8PX388iPinmlrfg7ZfEYfyBWofzNpx+2HpcYtTW4fuZLaOvlLzUwKj5s3eKlCEIQBi32WJ/xVTP5eXtqzqlp/f+EHmyYowrzu5N1q6z1gSP5avGfEOVj1tM/u3bv3evTXs2dP8Xf+DAtpfc9fdHR0SkrKoEGDlEplZmYmyZ/Big0EEEAAAQQQQMDtBEj+ZFi0syQEEEAAAQTsJ0DyZz9LekIAAQQkLEDyZ0naZ9zG2uTvuyPrjb8vCI+bpwjzOn79qLhz0JIeARF+j5O/hPB96SpFmNfVB5kzt057+6vhxiea3DaZ/IWGhubk5IjP7TScdezYMT8/P41G8/XXX0+aNMmwX8zttm7V33do+BOf9ml46eXllZmpf8bm0KFDf/rpJ3F/UVGRl5fX5cuXxR62bNFnmYIgREVFffTRR+K2yf+uib88dN5+w6EBXySaT/4EQThw/n7wskPPvh/b7/ME1cks8VxlzNmpq9MM/fzPuzsPXXwgvjSZ/B26+OCN8NQen8b7zFA9P3XX20sfp4aHLj544cPdmqrq1arLb4SnGjo0s9FG8rd/iSp0yLJegiAMWuK7JD5UTP7E+/wEQVDunKUI8zp353Rb7wFD8tfiPSPOxKrkb+3atdmP/i5dumRJ8qfRaCZMmHDmzBmSPzPXnUMIIIAAAggggID0BUj+JFx8MzUEEEAAAQRcL0Dy5/prwAwQQAABJwiQ/BmnepZsW5v8bT66wfgLAuP7vR4W5zxxz9+Tyd9ba141PtHktsnkz/A7fy1OGTJkSFJS0muvvbZ7927jQ2PHjrUw+TNzz5/lyd+Oo7d7zdprmEDXj/a0m/yJjauq9U8Hffb9WPGlMubsawtSxO38kopO47ddzioSX+YUlncavy2v+Jd7BMsq9E/1/OnwrepqfZPwbRfeWvI4+RMEQTEzPv5U1sCQfduO3BZ7MP9fi5I/1ePkb8Bin7IK/a8nTtzwZut7/ozfA4bkr8V7RpyM/6KuI1YOMj8x8agNT/s0dEvyZ6BgAwEEEEAAAQQQcEcBkj8nFNEMgQACCCCAgPsKkPy577Vj5ggggIAVAiR/LdK+q1evHj16tMVO45cdTP6yC+72C+/28tKeq/cvF6Og7Sd/MHnPn/nkr6qqqry8PCoqavTo0eXl5RUVj1OucePGtZX8RUdHjxgxwtfXV61WG3+LMWPGjHnz5hnvaeuev82bNxv/zt/48ePFs4KDg80kf++8805ISIih/4KSimffiz2W+VAQhL2nstr9nb+84oo9x++WlmsEQfh639VuH8eJXSljzv5qwvbkc/crNdXKmLP9P08wDCEIwgsf7o499kuMl1dc8X8nbLvyKBp8WFTea9Ze4+Rv2c6LA0MSn30/tqxCP4qZv7O3T+0+s315YrgizGva5om7z2xPTI8Tf+cvNfPJe/7+kfz1XNB56qbxc3bob/h7c3WgIAhtvQfMJ3+jVg3pvdB705ENu89szy745WGtrWdrx+Rv06ZN5UZ/rcdiDwIIIIAAAggggICkBEj+rCiGaYoAAggggIDnCZD8ed41Z8UIIOCRAiR/xqmeTqe7cOFCYmJii53GLzuY/AmCcOb2ycnfvD1gsc/r0a/EHPtW/KZA/zt/1tzzt3btWi+jvzFjxoj9mEn+srKyXnjhBeMQTjwlPT19xIgRffr06d+/v/iM0LaSP41GExkZOWDAgJ49e06dOjU7O1vswXzy169fvylTpogtxf+mXngweM6+oPnJU1en+f95r3jP3660Oz4zVD6fqDqN39bt4zifGaqYlBuCIDwsKh+5MOW5qbuen7pr6Lz9YmSof3hmzNkJK468uTj16Smxw0KTM+8+vuFPHGLPibvdPo57ekrs/O/PiXu+2XfV/897Ry1Kmbjy6F++O22c/N15WPqrCds/2XDCeJImtxftUSrCvIz/DVvR33zyF7x2RHjcvH7h3cauG5WRnS52a/I9YD75S7gQ91rUoN4LvRVhXskZj3++0eQk7Zj8Gb3FvLy9vU0Ox04EEEAAAQQQQAAB6QiQ/HlkWc+iEUAAAQQQsFSA5M9SKdohgAACbi0gm+SvqKgoOTn50KFD+fn5xkGdye3bt28fOnRo/379r82ZbGBmp8nkTzqlvpmZqNVqHx+f48ePm2njRoeUMWf/tNY+aymr0Dzz3s6jl3Lsu3zxd/7+sPY1+3ZLbwgggAACCCCAAAIItCVA8ufW5TmTRwABBBBAwNECJH+OFqZ/BBBAQBICskn+zGR19j3kvsnf+vXrX321/d8ObOtLBKntt2Py9+WezH5PPizULosl+bMLI50ggAACCCCAAAIIWC5A8ieJMptJIIAAAgggIFUBkj+pXhnmhQACCNhVgOTP2lzQHZO/goICHx+foKCg06dPW/6tgcRb2iX5yy+peOa9nX3+vPf4lVy7r5fkz+6kdIgAAggggAACCCBgXoDkz67lMp0hgAACCCAgNwGSP7ldUdaDAAIImBQg+fOE5M/8twMcRQABBBBAAAEEEEAAAXkIkPyZLHvZiQACCCCAAAKiAMkf7wQEEEDAIwRI/kj+5PEdB6tAAAEEEEAAAQQQQAABkj+PKONZJAIIIIAAArYKkPzZKsd5CCCAgFsJkPyR/PH9CAIIIIAAAggggAACCMhDgOTPrcpxJosAAggggICzBUj+nC3OeAgggIBLBEj+SP7k8R2HM1dRWVWZX5pXVlHqzEEZCwEEEEAAAQQQQACBdgVI/lxSVjMoAggggAAC7iJA8ucuV4p5IoAAAh0SIPmzV/K38fC6wMg+PRd0fi1qULsFucQbHD582N/f3zmTHKJM+vHwLcNYxerKTuO33c0tM+yxdqPnzPhuH8d1Gr+toLTS2nMtbH/kSqoizGuJKtTC9i5stn///oCAAOMJhIeHh4SEGO+xanvTpk2DBg3y8fFZuHChVSfSGAEEEEAAAQQQQMAJAiR/HSqPORkBBBBAAAG5C5D8yf0Ksz4EEEDgkQDJn12Sv+Lyol4LXnh1xYDYUz/uS1c5oaRfu3atl9HfmDFjxEHHjRsn7vb19R07duyJEyfanUxwcPDWrVuNm7kw+avUVK9PuFKi1hjPx9rtu7ll8kv+ei/0tiFUbp38nThx4tixY9aStmgfEhJC8tfChJcIIIAAAggggIAUBEj+KPQRQAABBBBAwIwAyZ8ZHA4hgAAC8hEg+bNL8nc956oizGvm1mlOq/arqqrKy8ujoqJGjx5dXl5eUVEhDj1u3LglS5ZoNJrc3FylUunr61tSUmJ+VpJK/sxP1cKjjk7+LJyGfZvZK/mzy6xI/uzCSCcIIIAAAggggIDdBUj+5FOrsxIEEEAAAQQcIEDy5wBUukQAAQSkJ0Dy1/Hkb9iK/oowL8M/w41Z205sUYR5LdozZ/I3b/sv6hoQ4VdaoQ/hzt05/e637wxY7PPG6qE/pG0Sq/3eC71n/DA1IMIvbHfIh5snDV6qSM5IbPeLgOjo6Ndff9242bhx45YuXSruuXHjhpeX1/nz57///vsRI0YYmu3atWvIkCGCIISGhgYEBLz44ot+fn4Bj/7KyvSP2RTv+duwYUOvXr38/f137twpnltVVbVixYqBAwf26tVr2rRp9+/fF/cHBweHh4dPmjQpICBg0qRJhYWFhrFMbhw4f7/vXxKeeS92xtcnB83eZ3ja58hFKYqZ8a2f9rntyO3en+199v3Yl6bv+XJPptinMubs639NDV526JW5+0csOHAlu9gwlsnk728Hrvf7POGZ93b6zlDNiTlbXlklCMLG/dcGfPGL80+Hbylmxhv6ab3xsDjHcKENT/s8feu4IswrZPuMgAi/NckrRq0aMmrVkNu5N0vLSxRhXm+tGTZ7+6eDlvQYu27UpXsXxT5NvgcEQTD5nhm//nXDoOKG+fdGWVnZF1980bNnz5dffnn58uWGp33u3bs3ICCgR48eLZ72eeHChbfffluhUPTu3Xv69OniDEtKSry8vBYtWvSHP/zh1VdfXbVqlbFG6+Tv1KlTwcHBPXr08Pf3//DDD8X3RlVVVf/+/ffu3Ws4d+jQoYa3k2EnGwgggAACCCCAAAL2EiD5k17NzYwQQAABBBCQkADJn4QuBlNBAAEEHCdA8tfx5G9/RsLGw2sVYV7j178edy7WkMqIKU7PBZ3D4+bFnvpx0R5laUXJ/cLs/ou7D16qWL1/+YQNbyjCvHae0j9ps/dC77HrRn6x7WP9D8jFhw5b0X/6lint1v9mkr/q6uoVK1a8+OKLhYWFxcXFL730Unp6utjh5MmTo6OjDZ2bvOfP29s7OjparVZv3brVx8envLxcEISYmJjBgwffunVLrVbPnDlz4sSJYifBwcGjRo0qLS2tqqoaO3bsV199Zei89UZeccUz7+2MSblRqaleo8rsNH6bIfkTBKH17/yVlmt+M2lH8jl9yphfUnH0Uo7YpzLm7G8n77h2Tx/4rU+4MjDklwDPZPL3/cGbJ6/mVmqqs/PK+v4lISJWH8IVlWn+592d527ki32+teTgsp2Pw7nWMxcEobyyPO5c7MrExca/8ycmf7N3fPrOVyN6Luj8zaE1ijCv746sF5M/RZjXYtX8zUc39FrwwpjVQYIgtPUeMCR/Ld4zh6+kxJ2L7bXghYBlvePOxcadi71fmG1yeuLOZcuWjRw5Mjc39969e0OHDjUkf+LR1r/z98477yxfvly/uvLyQ4cOic3E5E/MCIuKioYMGWIc4LVO/tLS0vbt21daWqpWqz/99FPDeyMyMvKDDz4Q+zx9+rSPj09paan4kv8igAACCCCAAAII2F2A5M9xtTM9I4AAAgggIAMBkj8ZXESWgAACCLQvQPLX8eRPEISrDzJbP+1TTP5Cd39hXM+LGeG2E1sEQcgpftBzQefx6/U37fVe6L08MTzhQpwizOvy/YwZP0wdu26U8Ykmt00mf927d/f393/ppZcCAgISEx/nYbNmzRJ/mC0nJ6dLly537941dGgy+evatatGo/+xvfLyci8vr5s3bwqCMG7cOENkeO3aNS8vr4KCAkEQgoOD161bJ3YYGRk5a9YsQ+etN7YfufXS9D3i/upqwWvabvPJX4la89+Td67de7mg5PETTcVzlTFnxyw+KG6Xlms6jd9muO3PZPJnPJPF29PHLz8i7pm25ueQzWf0gVyB+jeTdtx+2H4udeRKauvkLzUzKTxu3uClCkEQBiz2WZ7wVzH5e3lpz6pq/f2FH2yaoAjzupN3q633gCH5a/GeEedp+dM+hw4davjhxo0bN7ab/P3hD3/47LPPjN8SgiCIyd+pU6fE0ZcsWTJjxgyDYevkz3BIEIS0tDRfX19xz82bN7t27ZqbmysIwvz581vcbmh8FtsIIIAAAggggAACHRcg+Wu/BqYFAggggAACHixA8ufBF5+lI4CAJwmQ/Dk6+fvuyHrjAj48bp4izOv49aPizkFLegRE+D1O/hLC96WrFGFeVx9kztw67e2vhhufaHLbZPIXGhqak5MjPrfTcNaxY8f8/Pw0Gs3XX389adIkw34xtzMEReJ+8WmfhjZeXl6ZmfpnbA4dOvSnn34S9xcVFXl5eV2+fFnsYcsWfZYpCEJUVNRHH30kbpv875r4y0Pn7TccGvBFovnkTxCEA+fvBy879Oz7sf0+T1CdzBLPVcacnbo6zdDP/7y789DFB+JLk8nfoYsP3ghP7fFpvM8M1fNTd7299HFqeOjigxc+3K2pql6tuvxGeKqhQzMbbSR/+5eoQocs6yUIwqAlvkviQ8XkT7zPTxAE5c5ZijCvc3dOt/UeMCR/Ld4z4kwsT/58fX1TUlLEs8QnfBqvpfU9fzdu3Jg1a1a/R3+GZFdM/q5duyaeu379+nHjxhn6aZ383blz59NPP33llVcGDRrUt2/fF1980dB47NixGzdurKys7NWr14kTJwz72UAAAQQQQAABBBCwuwDJnydV86wVAQQQQAABqwVI/qwm4wQEEEDAHQVI/hyd/G0+usG4nje+3+thcc4T9/w9mfy9teZV4xNNbptM/gy/89filCFDhiQlJb322mu7d+82PjR27FgLkz8z9/xZnvztOHq716xffvit60d72k3+xNlWVeufDvrs+7HiS2XM2dcWPM638ksqOo3fdjmrSDyUU1jeafy2vOJf7hEsq9A/1fOnw7eqq/VNwrddeGvJ4+RPEATFzPj4U1kDQ/ZtO3Jb7MH8fy1K/lSPk78Bi33KKvS/njhxw5ut7/kzfg8Ykr8W7xlxMv6Luo5YOcj8xMSjgYGBu3btErd/+OGHdu/5M/R54sSJrl27XrhwwXDP39GjjyPqsLCwTz75xNBy3rx5oaGhhpfi/aChoaFqtVoQhKNHj3bt2tVwdMeOHaNHj05MTBw6dKhhJxsIIIAAAggggAACjhAg+XPHqpw5I4AAAggg4DQBkj+nUTMQAggg4EoBkj8nJ3/ZBXf7hXd7eWnP1fuXi1HQ9pM/mLznz3zyV1VVVV5eHhUVNXr06PLy8oqKxynXuHHj2kr+oqOjR4wY4evrK8Yzhi8aZsyYMW/ePMNLQRDauudv8+bNxr/zN378ePGs4OBgM8nfO++8Y/yMx4KSimffiz2W+VAQhL2nstr9nb+84oo9x++WlusfPfr1vqvdPo4TB1XGnP3VhO3J5+5XaqqVMWf7f55gvIQXPtwde+yXGC+vuOL/Tth25VE0+LCovNesvcbJ37KdFweGJD77fmxZhX4UM39nb5/afWb78sRwRZjXtM0Td5/ZnpgeJ/7OX2rmk/f8/SP567mg89RN4+fs0N/w9+bqQEEQ2noPmE/+Rq0a0nuh96YjG3af2Z5d8MvDWlvPdvny5e+++25VVVVFRcU777zTbvK3e/du8WmcGRkZXbt2vXHjhiH5e/fdd0tKSq5fv+7n5xcX91heEIRNmzaJbzzD6CNGjPjhB/07ubKycvr06cbJX1lZma+v74gRI9asWWNozwYCCCCAAAIIIICAIwRI/lxZXTM2AggggAACkhcg+ZP8JWKCCCCAgD0ESP6cnPwJgnDm9snJ37w9YLHP69GvxBz7Viz49b/zZ809f2vXrvUy+hszZozYj5nkLysr64UXXjAO4cRT0tPTR4wY0adPn/79+4vPCG0r+dNoNJGRkQMGDOjZs+fUqVOzs7PFHswnf/369ZsyZYrYUvxv6oUHg+fsC5qfPHV1mv+f94r3/O1Ku+MzQ+XziarT+G3dPo7zmaGKSdFHUA+LykcuTHlu6q7np+4aOm+/GBnqH54Zc3bCiiNvLk59ekrssNDkzLuPb/gTh9hz4m63j+OenhI7//tz4p5v9l31//PeUYtSJq48+pfvThsnf3celv5qwvZPNrT/IMpFe5SKMC/jf8NW9Def/AWvHREeN69feLex60ZlZKeLkzH5HjCf/CVciHstalDvhd6KMK/kjMc/3yj21uK/arU6JCRkxIgRwcHBc+bMMSR/wcHBgwYN8vX19fHxGTRo0IgRI8QTP//8c39/f19f31deecVw96f4tM81a9b4P/pbuXKl8SilpaUffPCBj49P9+7di4r08j///PNrr70WHBz8xz/+cd26dcbJnyAIs2fP7ty5c1bW4ye1GnfFNgIIIIAAAggggIAdBUj+7FEl0wcCCCCAAAKyFSD5k+2lZWEIIICAsQDJn12SPzvW6o7rSq1W+/j4HD9+3HFDOLNnZczZP621z1rKKjTPvLfz6KUc+85f/J2/P6x9zb7dOqc3Mfm7c+eOXYaLjo6eOHGiXbqiEwQQQAABBBBAAAEzAiR/xtUu2wgggAACCCDQQoDkrwUILxFAAAF5CpD8eU7yt379+ldfbf+3A818jyCpFVjTbQAAIABJREFUQ3ZM/r7ck9nvyYeF2mWlJH8iY0FBQf/+/Y0fFmoXXjpBAAEEEEAAAQQQaC1A8ifPup1VIYAAAgggYCcBkj87QdINAgggIG0Bkj9PSP4KCgp8fHyCgoJOnz7d+tsBN91jl+Qvv6Timfd29vnz3uNXcu3uQPInCMLixYsVCsWcOXPszkuHCCCAAAIIIIAAAq0FSP6kXX8zOwQQQAABBFwsQPLn4gvA8AgggIBzBEj+PCH5a/2NAHsQQAABBBBAAAEEEEBAfgIkf86poxkFAQQQQAABNxUg+XPTC8e0EUAAAesESP5I/uT3fQcrQgABBBBAAAEEEEDAMwVI/qyrh2mNAAIIIICAhwmQ/HnYBWe5CCDgqQIkfyR/nvmdCKtGAAEEEEAAAQQQQEB+AiR/nlrZs24EEEAAAQQsEiD5s4iJRggggIC7C5D8kfzJ7/sOVoQAAggggAACCCCAgGcKkPy5e4XO/BFAAAEEEHCoAMmfQ3npHAEEEJCKAMkfyZ9nfifCqhFAAAEEEEAAAQQQkJ8AyZ9UKm3mgQACCCCAgCQFSP4keVmYFAIIIGBvAZI/kj/5fd/BihBAAAEEEEAAAQQQ8EwBkj97V8z0hwACCCCAgKwESP5kdTlZDAIIINCWAMkfyZ9nfifCqhFAAAEEEEAAAQQQkJ8AyV9blS/7EUAAAQQQQECtVpP88TZAAAEEPEKA5I/kT37fd7AiBBBAAAEEEEAAAQQ8U4DkzyPKeBaJAAIIIICArQIkf7bKcR4CCCDgVgIkfyR/nvmdCKtGAAEEEEAAAQQQQEB+AiR/blWOM1kEEEAAAQScLUDy52xxxkMAAQRcIkDyR/Inv+87WBECCCCAAAIIIIAAAp4pQPLnkrKaQRFAAAEEEHAXAZI/d7lSzBMBBBDokADJH8mfZ34nwqoRQAABBBBAAAEEEJCfAMlfh8pjTkYAAQQQQEDuAiR/cr/CrA8BBBB4JEDyR/Inv+87WBECCCCAAAIIIIAAAp4pQPJHoY8AAggggAACZgRI/szgcAgBBBCQjwDJH8mfZ34nwqoRQAABBBBAAAEEEJCfAMmffGp1VoIAAggggIADBEj+HIBKlwgggID0BEj+SP7k930HK0IAAQQQQAABBBBAwDMFSP6kV3MzIwQQQAABBCQkQPInoYvBVBBAAAHHCZD8kfx55ncirBoBBBBAAAEEEEAAAfkJkPw5rnamZwQQQAABBGQgQPIng4vIEhBAAIH2BUj+SP7k930HK0IAAQQQQAABBBBAwDMFSP7ar4FpgQACCCCAgAcLkPx58MVn6Qgg4EkCJH8kf575nQirRgABBBBAAAEEEEBAfgIkf55UzbNWBBBAAAEErBYg+bOajBMQQAABdxQg+SP5k9/3HawIAQQQQAABBBBAAAHPFCD5c8eqnDkjgAACCCDgNAGSP6dRMxACCCDgSgGSP5I/z/xOhFUjgAACCCCAAAIIICA/AZI/V1bXjI0AAggggIDkBUj+JH+JmCACCCBgDwGSP5I/+X3fwYoQQAABBBBAAAEEEPBMAZI/e1TJ9IEAAggggIBsBUj+ZHtpWRgCCCBgLEDyR/Lnmd+JsGoEEEAAAQQQQAABBOQnQPJnXO2yjQACCCCAAAItBEj+WoDwEgEEEJCnAMkfyZ/l33dcil5+Zu7nrdunvjn8wMhX4v1eqiwuan2UPQgggAACCCCAAAIIIOAcAZI/edbtrAoBBBBAAAE7CZD82QmSbhBAAAFpC5D8ST/5O79o7uX1q4uvXkkc0sf4+4K29qe+OTz35PGbP245+eePjdu3tX1s6sTbsdvbOmq8v63kTxAE9f17JH/GVmwjgAACCCCAAAIIIOB8AZI/adffzA4BBBBAAAEXC5D8ufgCMDwCCCDgHAGSP5I/kj/nfyPDiAgggAACCCCAAAIIOEKA5M85dTSjIIAAAggg4KYCJH9ueuGYNgIIIGCdAMlfx5O/wsLCP/3pT71791YoFGPGjLl3756ZGr68sKY0R2jxz0x7QRDaurevrf3m7/nTlJbejt1+7P0JQlXVxYi/pr45PGFgz6SggalvDk99c7imrEwQhMqCgpOzPkoKGrgvoO+x98bnnzsjzvBS9PKTn00//sm0fS/7HX13XNGVy4aZm7znT1NacjEy/MCooUlBA8+FzdGUlgqCcDHir5lffVl6+5bhXDYQQAABBBBAAAEEEEDALgIkf9bVw7RGAAEEEEDAwwRI/jzsgrNcBBDwVAGSv44nf5GRkRMnTlSr1VVVVadPn87PzzdTtKfMq4kZ2vJfdZWZM4S80ycLMy5WFhXeVe02btfW/ux9e8tzcoqvX33481Hj9rknj58NDdkX0PfkZ9OzkxIMh1rf81eek3Pzxy0V+flCVdXNH7ckDvHXlOlDu0vRy+P7dH947Eh1ZWXm6pUH335NqHo8dZPJ39m5f0n705SK/DxNacmpv3xyITxUEISiK5kXI8P3DxuUNu2Pd/bEij0bJsMGAggggAACCCCAAAII2CxA8ueplT3rRgABBBBAwCIBkj+LmGiEAAIIuLsAyV/Hk7/ly5ePHj06IyOjurq63RI9N1O4c6ymxb92z+pggzt7YlPefPXolHE3t31fWVDQorfWyd8TDaqq9vb1KczMEJO/tKmTxKOa0pJ4/27ifpO/86cpLo73e6no8iWxfcHFC8a/U1it0Tw4lHJm9mf62wEXzn1iRF4ggAACCCCAAAIIIICATQIkf+5eoTN/BBBAAAEEHCpA8udQXjpHAAEEpCJA8tfx5K+kpGTx4sVBQUE+Pj6zZs0qKSkxU6SX5dUU3RVa/DPT3i6HrmxYkxTY/8KSBXmnT7busHXyV1VRkREVcfCdUQdGBx4YHRjv3y3//Fkx+TsdMsvQQ+LLfjnHDosvW9/zV3QlM97vpYNvv5Yq/ntrRFJgf03pLzhl2XevfbchdcyII5P/IFgQmhrGZQMBBBBAAAEEEEAAAQRMCpD8SaXSZh4IIIAAAghIUoDkT5KXhUkhgAAC9hYg+et48mcoubOysgIDA7/++mvDntYbNjzts3UnNuypLCy4sTXm8MS3Ul4PylwTVXz9qqGTtA/+eDt2m+GlIAhXNqw5OmVcRV6uIAjVlRV7+/rkn9f/1N+l6OUt7vkrupIpnliRlxvv95LxDYWVxUXxfi+V5+QY96z/EcHCglvbt6ZNnbT/1cEZUcuKr11p0YCXCCCAAAIIIIAAAgggYJsAyZ+9K2b6QwABBBBAQFYCJH+yupwsBgEEEGhLgOSv48lfamrq9evXBUHIy8sLCgr68ccfzVTpOReF24db/jPT3u6Hii5fuhi5OClwgOEn+s4o/5y+ZKHxQBcjF5+d+xdxz/Utm+L9XjIkf/rf+Us7+vh3/t4ZZXyvXlLQwOx9e437OTPns9NffFqe+1AQhNK7d7L3xQuCcDpk5snPpt9P2V+t0Rg3ZhsBBBBAAAEEEEAAAQQ6KEDy11bly34EEEAAAQQQUKvVJH+8DRBAAAGPECD563jyt2nTpiFDhvj4+PTt23fBggUadwi0qisrDN8pFF66eGjcm/uHD05+LUBTVqb/0b6cBz//v/cOT3z7+PSp17dsShzsZ0j+Tn42/cSMDxMH+x2dMs74xkFBEO4dSDow8pXEwX6XVkWKnWtKSy8uX3JgdOC+l/0Ovv3a9c3fiDcRGoZmAwEEEEAAAQQQQAABBOwoQPLnEWU8i0QAAQQQQMBWAZI/W+U4DwEEEHArAZK/jid/dizU6QoBBBBAAAEEEEAAAQQQsFmA5M+tynEmiwACCCCAgLMFSP6cLc54CCCAgEsESP5I/mz+WoETEUAAAQQQQAABBBBAQFICJH8uKasZFAEEEEAAAXcRIPlzlyvFPBFAAIEOCZD8kfxJ6qsKJoMAAggggAACCCCAAAI2C5D8dag85mQEEEAAAQTkLkDyJ/crzPoQQACBRwIkfyR/Nn+twIkIIIAAAggggAACCCAgKQGSPwp9BBBAAAEEEDAjQPJnBodDCCCAgHwESP5I/iT1VQWTQQABBBBAAAEEEEAAAZsFSP7kU6uzEgQQQAABBBwgQPLnAFS6RAABBKQnQPJH8mfz1wqciAACCCCAAAIIIIAAApISIPmTXs3NjBBAAAEEEJCQAMmfhC4GU0EAAQQcJ0DyR/Inqa8qmAwCCCCAAAIIIIAAAgjYLEDy57jamZ4RQAABBBCQgQDJnwwuIktAAAEE2hcg+SP5s/lrBU5EAAEEEEAAAQQQQAABSQmQ/LVfA9MCAQQQQAABDxYg+fPgi8/SEUDAkwRI/hya/GV+9eWZuZ9L6rsAJoMAAggggAACCCCAAAJyFSD586RqnrUigAACCCBgtQDJn9VknIAAAgi4owDJ3/9n797/mrry/Y//PZzLd9qTsSgagWBTlJaCtrZaL9MRO1adQe1Y7eXUVtvR0xZ7vHxVtFUcrU5b2waSEAggIBdDQcSAISAXQSSSQEIu6/fvI7Pb/c0kEMUEcnv14aOurKy99trP5S+f/X7sHZK/ZL3rwXUhgAACCCCAAAIIIJBqAiR/iViVs2YEEEAAAQQWTIDkb8GoORECCCAQSwGSv2gmf17vSK2xdc+OsdamQc01Y75al5WuUyqM+Wpjvnqs+YZ830G7THHv+ysNm1+rylNV5ak8Dkfj1k3Wy2XuiUfyGBoIIIAAAggggAACCCCAwJwESP5iWV1zbgQQQAABBOJegOQv7reIBSKAAALRECD5i0ry5+i1dJUcNqiV9RvXWi+XeSYdUn0+29s+tcsU19evdt4fFkJMDg54p6dH6oymvcW6zOdMe4tH62uFzzenCp/BCCCAAAIIIIAAAggggADJXzSqZOZAAAEEEEAgaQVI/pJ2a7kwBBBAIFCA5C/C5G+83dSw+TVjvtp84qij3xp0ryFM8jfw4/dBg4UQHrv93vdXGos2VK3K7r34degAehBAAAEEEEAAAQQQQACB2QRI/gKrXdoIIIAAAgggECRA8hcEwkcEEEAgOQVI/iJM/kZqjXrVktZd24crtd7p6aAKPEzy9/BmS9Bg6aPtVnvnkUP6nIzOwwdnHEAnAggggAACCCCAAAIIIDCjAMlfctbtXBUCCCCAAAJREiD5ixIk0yCAAALxLUDyF2HyJ4TwuaeHdOXNO4r0qsXtB/b7f8/vt3d1mo+XmPbtDq3JtcsU4+2mwH5Hv7X71LGawtyaNXmWb864xh4EfksbAQQQQAABBBBAAAEEEHisAMlffNffrA4BBBBAAIEYC5D8xXgDOD0CCCCwMAIkf5Enf3L57RwduXv2VE1h7lhTg9TZd/VS3esFPnfws4ChyV9Vnqrj4Ifj7W3ybDQQQAABBBBAAAEEEEAAgTkJkPwtTB3NWRBAAAEEEEhQAZK/BN04lo0AAgjMTYDkL4rJn1yTy1Gfx25v2vZm5YqlhtxMOQ4UQoQmf/Ih8iQ0EEAAAQQQQAABBBBAAIE5CZD8za0eZjQCCCCAAAIpJkDyl2IbzuUigECqCpD8zUfyN6finMEIIIAAAggggAACCCCAQFQESP5StbLnuhFAAAEEEHgiAZK/J2JiEAIIIJDoAiR/JH9RucXAJAgggAACCCCAAAIIIBBzAZK/RK/QWT8CCCCAAALzKkDyN6+8TI4AAgjEiwDJH8lfzG9PsAAEEEAAAQQQQAABBBCIigDJX7xU2qwDAQQQQACBuBQg+YvLbWFRCCCAQLQFSP5I/qJyi4FJEEAAAQQQQAABBBBAIOYCJH/RrpiZDwEEEEAAgaQSIPlLqu3kYhBAAIHZBEj+SP5ifnuCBSCAAAIIIIAAAggggEBUBEj+Zqt86UcAAQQQQAABp9NJ8sc/AwQQQCAlBEj+SP6icouBSRBAAAEEEEAAAQQQQCDmAiR/KVHGc5EIIIAAAgg8rQDJ39PKcRwCCCCQUAIkfyR/Mb89wQIQQAABBBBAAAEEEEAgKgIkfwlVjrNYBBBAAAEEFlqA5G+hxTkfAgggEBMBkr8FTv58Ho9GkebotUSlsH+6Sa6vXz2oufZ0xy78UQ9u1Fc+v2zhz8sZEUAAAQQQQAABBBBIOAGSv5iU1ZwUAQQQQACBRBEg+UuUnWKdCCCAQEQCJH/zmvzdOfalaf+ewPsFc03+qvJUfVf+Ls0wPT6uUaTZOjsCJ3yKdtSTv7HmxsaijTqlovy5/5jreoyFKwfLf5KPanhzXf93V+SPQgiSv0AN2ggggAACCCCAAAIIhBEg+YuoPOZgBBBAAAEEkl2A5C/Zd5jrQwABBP4pQPJH8hfmxsETfjXebhos/8n6bdlck7/hSm11/vPC65VPRPInU9BAAAEEEEAAAQQQQGCuAiR/FPoIIIAAAgggEEaA5C8MDl8hgAACySNA8hfN5M/rHak1tu7ZMdbaNKi5ZsxX67LSdUqFMV9tzFePNd8QQkjP/PX+/bwxX61VKm59dkAq5hu3brJeLnNPPAqq7cM882e9XGYszNUuX9RYtNHR1ysdeO/7KzWv5GmViuoXc25//ql3elrqf9BYX7MmT6dUtH/8ft3rBfLbPseaG+s3vqpdvqjmlbzR6zXy2W2dHRVLfjekr6hZk1e1Mqt551b5q9kaI7XVsyZ/ATKBh19fv7rv6iWpp/NvHxvz1RUZz+hzMiQxz9SU/Myf5XypXrW4csXSgZ9+EELYe7qbd24drtT63L9eYOC0tBFAAAEEEEAAAQQQSE0Bkr/kqdW5EgQQQAABBOZBgORvHlCZEgEEEIg/AZK/qCR/jl5LV8lhg1pZv3Gt9XKZZ9Ih3WiY7W2frbu2u+0TE+auioxnxn8xCSFG6oymvcW6zOdMe4tH62uFzyfNMFvy1/+Py4bczInuOz6Px/L16Zo1edKTcwM/fm/r+MXndjtHR2rW5PWcPi6EcNtsWqXi3g9XfW635cI5jSJNSv7slp6KjGeG9BXC6x1radIqFZMD96Tz2jo7NIv+ve39d7wulxDiSX6YcMbkbzYZIcRoQ51BrZSzSem8Mz7zV/7cf/ScPu51Ovu/u6JVKrzT016Xq/+7K41b3tDnZHQeOTRh7pIO5/8IIIAAAggggAACCKSyAMlf/NXcrAgBBBBAAIE4EiD5i6PNYCkIIIDA/AmQ/EWY/I23mxo2v2bMV5tPHHX0W4PuMsyW/I3dbJZG1m9ce+/7//+zdh67/d73VxqLNlStyu69+LUQoipPpV2m0KsW61WLddnp8u/81b1eIA3wz+PzaZWKR3duB53dfPKrll1vCyEGK3425Gb++q3Pp1ctlpK/2/9zqHXXdvmo5p1bLWXnpI/+5E+RNjU0IH/72EZQ8hdeRgjRuOUNy/nSoGlnTP4qFv8fn8cjhPC6XBpF2mR/n3zU1NBAT+lJY+HKunUFD27Uy/00EEAAAQQQQAABBBBIQQGSv/mrnZkZAQQQQACBJBAg+UuCTeQSEEAAgccLkPxFmPyN1Br1qiWtu7YPV2qDHl8TQsyW/MmP0DUWbbBeuhB4S8J2q73zyCH/o2yHD0rJ392zp5z3h533hye6zXLyp8tKr1qZZSzMlf5Urlg62lAnhBhrabrxp83VL62oylPpstKbtm8RQljKztVvfFU+S+2rL0nJX+vu7brsdHkSQ26m+XiJNMzW2VGe/p/yIU/SCEr+wss8bLupy0r3TE4GzTxj8lf5/DJ5mEaRZu/plj/63O6R2mrTvl267PTB8h/lfhoIIIAAAggggAACCKSgAMnf42tgRiCAAAIIIJDCAiR/Kbz5XDoCCKSSAMlfhMmf/4k79/SQrrx5R5Fetbj9wH7/7/n99q5O8/ES077dgXccpN/5C03+HP3W7lPHagpza9bkWb454xp7IB0129s+/b/VV/5T4Mz+R+KcTu3SZ/0B2D8XYD5e0vT2H/3P/Gl/Nr78gjzYoFbKz/x1fPKB3B/YkH7nL7Dnse2g5C+8TPPOIvOJo6FzNv7xjf7vvg3sf3Cjfsbk72HbzVuffqTPyWjcumlQc83rdAYeRRsBBBBAAAEEEEAAgRQUIPlLpWqea0UAAQQQQGDOAiR/cybjAAQQQCARBUj+Ik/+5BsKztGRu2dP1RTmjjU1SJ19Vy/VvV7gc0/LY2ZL/qryVB0HPxxvb5NHSo3Zkr++K3+vWb1KevrN/ch279o/fB6P22bT/P7fHNZeIcT0+EPjyy9IyZ974pF2+e8fmlr9PyhYWy3/zt9Et1m7fNFIndHn8XidztHrNY4+/7FCiLklfz6f1+UartKVP/cfXpcr9NnHIJkJc5dOqXDbbNK5Av9v2rfr1qGPAntmTP4mzF3VL+aYT341OTiH95EGTksbAQQQQAABBBBAAIHkEyD5S8SqnDUjgAACCCCwYAIkfwtGzYkQQACBWAqQ/EUx+ZNvHMhRn8dub9r2ZuWKpYbcTCkOnC35kw+RJ5EasyV/Qgjr5bKa1at0SoXhheVt770jvF4hRN+3F42FKxuLNrbu3n7rswNS8ud/C2hTQ926gvpNa037dhsLV0rP/En9DZtf02U+p8v2vxpU/qnCOSV/o/W1GkWa/Ee7fFHQVcgfpcs07S2+/fmncmdg41FXZ+3a/Er1MkNupmdqSggxY/Lnc7sDj6KNAAIIIIAAAggggAACQgiSv1hW15wbAQQQQACBuBcg+Yv7LWKBCCCAQDQESP7mI/njpkMYAUdfr3bps86R+2HG8BUCCCCAAAIIIIAAAgg8hQDJXzSqZOZAAAEEEEAgaQVI/pJ2a7kwBBBAIFCA5I/k7yluKERyyFhL08DPP0QyA8cigAACCCCAAAIIIIDAjAIkf4HVLm0EEEAAAQQQCBIg+QsC4SMCCCCQnAIkfyR/M94yoBMBBBBAAAEEEEAAAQQSToDkLznrdq4KAQQQQACBKAmQ/EUJkmkQQACB+BYg+SP5S7jbGSwYAQQQQAABBBBAAAEEZhQg+Yvv+pvVIYAAAgggEGMBkr8YbwCnRwABBBZGgOSP5G/GWwZ0IoAAAggggAACCCCAQMIJkPwtTB3NWRBAAAEEEEhQAZK/BN04lo0AAgjMTYDkj+Qv4W5nsGAEEEAAAQQQQAABBBCYUYDkb271MKMRQAABBBBIMQGSvxTbcC4XAQRSVYDkj+RvxlsGdCKAAAIIIIAAAggggEDCCZD8pWplz3UjgAACCCDwRAIkf0/ExCAEEEAg0QVI/hY4+fN5PBpFmqPXEsObCNfXrx7UXIvhAuZ06gc36iufXzanQxiMAAIIIIAAAggggEBqCpD8JXqFzvoRQAABBBCYVwGSv3nlZXIEEEAgXgRI/uY1+btz7EvT/j2BNx3mmvxV5an6rvxdmmF6fFyjSLN1dgRO+BTtqCd/XUePGAteqMh4pvqlFZavT89pScbClYPlP8mHNLy5rv+7K/JHIQTJX6AGbQQQQAABBBBAAAEEwgiQ/MVLpc06EEAAAQQQiEsBkr+43BYWhQACCERbgOSP5C/MjYMn/Krj0H+PtTRNPxwbra/VLlPcu/aPJzxwuFJbnf+88Hrl8SR/MgUNBBBAAAEEEEAAAQTmKkDyF+2KmfkQQAABBBBIKgGSv6TaTi4GAQQQmE2A5C+ayZ/XO1JrbN2zY6y1aVBzzZiv1mWl65QKY77amK8ea74hhJCe+ev9+3ljvlqrVNz67IBUzDdu3WS9XOaeeBRU24d55s96ucxYmKtdvqixaKOjr1c68N73V2peydMqFdUv5tz+/FPv9LTU/6CxvmZNnk6paP/4/brXC+S3fY41N9ZvfFW7fFHNK3mj12vks9s6OyqW/G5IX1GzJq9qZVbzzq3yV+EbzTuLfvlof/CYAJnAr66vX9139ZLU0/m3j4356oqMZ/Q5GZKYZ2pKfubPcr5Ur1pcuWLpwE8/CCHsPd3NO7cOV2p97l8vMHBa2ggggAACCCCAAAIIpKYAyd9slS/9CCCAAAIIIOB0Okn++GeAAAIIpIQAyV9Ukj9Hr6Wr5LBBrazfuNZ6ucwz6ZBuNMz2ts/WXdvd9okJc1dFxjPjv5iEECN1RtPeYl3mc6a9xaP1tcLnk2aYLfnr/8dlQ27mRPcdn8dj+fp0zZo86cm5gR+/t3X84nO7naMjNWvyek4fF0K4bTatUnHvh6s+t9ty4ZxGkSYlf3ZLT0XGM0P6CuH1jrU0aZWKyYF70nltnR2aRf/e9v47XpdLCPGEP0zoc08bcjPl15NKB84oI4QYbagzqJVyNimdd8Zn/sqf+4+e08e9Tmf/d1e0SoV3etrrcvV/d6Vxyxv6nIzOI4cmzF3S4fwfAQQQQAABBBBAAIFUFiD5S4kynotEAAEEEEDgaQVI/p5WjuMQQACBhBIg+Ysw+RtvNzVsfs2YrzafOOrotwbdZZgt+Ru72SyNrN+49t73//9n7Tx2+73vrzQWbahald178WshRFWeSrtMoVct1qsW67LT5d/5q3u9QBrgn8fn0yoVj+7cDjq7+eRXLbveFkIMVvxsyM389VufT69aLCV/t//nUOuu7fJRzTu3WsrOSR/9yZ8ibWpoQP72SRodn3zQWLTB5/EIIcLLCCEat7xhOV8aNO2MyV/F4v8jzel1uTSKtMn+PvmoqaGBntKTxsKVdesKHtyol/tpIIAAAggggAACCCCQggIkfwlVjrNYBBBAAAEEFlqA5G+hxTkfAgggEBMBkr8Ik7+RWqNetaR11/bhSm3Q42tCiNmSP/kRusaiDdZLFwJvSdhutXceOeR/lO3wQSn5u3v2lPP+sPP+8ES3WU7+dFnpVSuzjIW50p/KFUtHG+qEEGMtTTf+tLn6pRVVeSpdVnrT9i1CCEvZufqNr8pnqX31JSn5a929XZedLk9iyM00Hy+Rhtk6O8rT/1M+5EkaXSWHr7+xxmO3S4PDyzxsu6nLSvdMTgbNPGPyV/n8MnmYRpFm7+mWP/rc7pHaatO+Xbrs9MHyH+V+GggggACZC5EdAAAgAElEQVQCCCCAAAIIpKAAyV9MympOigACCCCAQKIIkPwlyk6xTgQQQCAiAZK/CJM//xN37ukhXXnzjiK9anH7gf3+3/P77V2d5uMlpn27A+84SL/zF5r8Ofqt3aeO1RTm1qzJs3xzxjX2QDpqtrd9+n+rr/ynwJmFEF6nU7v0WX8A9s8FmI+XNL39R/8zf9qfjS+/IA82qJXyM38dn3wg9wc2pN/5C+wJ3/bHfhtecdsnAoeFkWneWWQ+cTRwsNRu/OMb/d99G9j/4Eb9jMnfw7abtz79SJ+T0bh106DmmtfpDDyKNgIIIIAAAggggAACKShA8hdReczBCCCAAAIIJLsAyV+y7zDXhwACCPxTgOQv8uRPvqHgHB25e/ZUTWHuWFOD1Nl39VLd6wU+97Q8ZrbkrypP1XHww/H2Nnmk1Jgt+eu78vea1aukp9/cj2z3rv3D5/G4bTbN7//NYe0VQkyPPzS+/IKU/LknHmmX//6hqdX/g4K11fLv/E10m7XLF43UGX0ej9fpHL1e4+jzHyuEmFPyd/vzz+rWFbjGHnhdLq/L5XO7pUnk/wfJTJi7dEqF22aTB8gN075dtw59JH8UQsyY/E2Yu6pfzDGf/GpycG7vIw2cmTYCCCCAAAIIIIAAAkkmQPJHoY8AAggggAACYQRI/sLg8BUCCCCQPAIkf1FM/uS7BnLU57Hbm7a9WbliqSE3U4oDZ0v+5EPkSaTGbMmfEMJ6uaxm9SqdUmF4YXnbe+8Ir1cI0fftRWPhysaija27t9/67ICU/PnfAtrUULeuoH7TWtO+3cbCldIzf1J/w+bXdJnP6bL9rwaVf6rwyZM/6bf3NIo0+Y980qBrkZ6PFEKY9hbf/vzT0G+FEI+6OmvX5leqlxlyMz1TU7Mlf6Hh4oyz0YkAAggggAACCCCAQEoJkPwlT63OlSCAAAIIIDAPAiR/84DKlAgggED8CZD8zUfyl1I3F+Z6sY6+Xu3SZ50j9+d6IOMRQAABBBBAAAEEEEAgvADJX/zV3KwIAQQQQACBOBIg+YujzWApCCCAwPwJkPyR/IW/dxD1b8damgZ+/iHq0zIhAggggAACCCCAAAIIkPzNX+3MzAgggAACCCSBAMlfEmwil4AAAgg8XoDkj+SP+yMIIIAAAggggAACCCCQHAIkf4+vgRmBAAIIIIBACguQ/KXw5nPpCCCQSgIkfyR/yXGPg6tAAAEEEEAAAQQQQAABkr9Uqua5VgQQQAABBOYsQPI3ZzIOQAABBBJRgOSP5I/7IwgggAACCCCAAAIIIJAcAiR/iViVs2YEEEAAAQQWTIDkb8GoORECCCAQSwGSP5K/5LjHwVUggAACCCCAAAIIIIAAyV8sq2vOjQACCCCAQNwLkPzF/RaxQAQQQCAaAiR/JH/cH0EAAQQQQAABBBBAAIHkECD5i0aVzBwIIIAAAggkrQDJX9JuLReGAAIIBAqQ/JH8Jcc9Dq4CAQQQQAABBBBAAAEESP4Cq13aCCCAAAIIIBAkQPIXBMJHBBBAIDkFSP4WJvkzFq4cLP9JvhNx59iXpv175I80EEAAAQQQQAABBBBAAIHIBUj+krNu56oQQAABBBCIkgDJX5QgmQYBBBCIbwGSvwVI/oYrtdX5zwuvV67kSf5kChoIIIAAAggggAACCCAQLQGSv/iuv1kdAggggAACMRYg+YvxBnB6BBBAYGEESP6imfx5vSO1xtY9O8ZamwJL9+vrV/ddvST1DGquGfPVuqx0nVJhzFcb89VjzTekr2ydHRVLfjekr6hZk1e1Mqt551Z7T3fzzq3DlVqfezpwQtoIIIAAAggggAACCCCAQKgAyd/C1NGcBQEEEEAAgQQVIPlL0I1j2QgggMDcBEj+opL8OXotXSWHDWpl/ca11stlnkmHXISPNtQZ1Erv9L9EdzM+82fr7NAs+ve299/xulxCCEevxety9X93pXHLG/qcjM4jhybMXfK0NBBAAAEEEEAAAQQQQACBIAGSv7nVw4xGAAEEEEAgxQRI/lJsw7lcBBBIVQGSvwiTv/F2U8Pm14z5avOJo45+a1DhLYRo3PKG5XxpUP+syZ8ibWpoIGiwEGJqaKCn9KSxcGXduoIHN+pDB9CDAAIIIIAAAggggAACCJD8pWplz3UjgAACCCDwRAIkf0/ExCAEEEAg0QVI/iJM/kZqjXrVktZd24crtUEP9gkhHrbd1GWleyYng+5BzJb8laf/Z9BI6aPP7R6prTbt26XLTh8s/3HGMXQigAACCCCAAAIIIIBAiguQ/CV6hc76EUAAAQQQmFcBkr955WVyBBBAIF4ESP4iTP6EED739JCuvHlHkV61uP3Afv/v9vl80h2H5p1F5hNHQ+8+mI+XmPbtDuqXfucvqPNh281bn36kz8lo3LppUHPN63QGDeAjAggggAACCCCAAAIIICAJkPzFS6XNOhBAAAEEEIhLAZK/uNwWFoUAAghEW4DkL/LkT77L4BwduXv2VE1h7lhTgxBiwtylUyrcNps8QG70Xb1U93qBz/0vP/4XmvxNmLuqX8wxn/xqcnCGV4DKs9FAAAEEEEAAAQQQQAABBIQQJH/RrpiZDwEEEEAAgaQSIPlLqu3kYhBAAIHZBEj+opj8yfcapEjPtLf49uefyp2BDY/d3rTtzcoVSw25mVJMKIQITf58bnfgUbQRQAABBBBAAAEEEEAAgTACJH+zVb70I4AAAggggIDT6ST5458BAgggkBICJH/zkfwJIRx9vdqlzzpH7ocpy/kKAQQQQAABBBBAAAEEEIiiAMlfSpTxXCQCCCCAAAJPK0Dy97RyHIcAAggklADJ3zwlf2MtTQM//xDFGp6pEEAAAQQQQAABBBBAAIHwAiR/CVWOs1gEEEAAAQQWWoDkb6HFOR8CCCAQEwGSv3lK/sIX5HyLAAIIIIAAAggggAACCERdgOQvJmU1J0UAAQQQQCBRBEj+EmWnWCcCCCAQkQDJH8lf1G83MCECCCCAAAIIIIAAAgjERIDkL6LymIMRQAABBBBIdgGSv2TfYa4PAQQQ+KcAyR/JX0xuSXBSBBBAAAEEEEAAAQQQiLoAyR+FPgIIIIAAAgiEESD5C4PDVwgggEDyCJD8kfxF/XYDEyKAAAIIIIAAAggggEBMBEj+kqdW50oQQAABBBCYBwGSv3lAZUoEEEAg/gRI/kj+YnJLgpMigAACCCCAAAIIIIBA1AVI/uKv5mZFCCCAAAIIxJEAyV8cbQZLQQABBOZPgOSP5C/qtxuYEAEEEEAAAQQQQAABBGIiQPI3f7UzMyOAAAIIIJAEAiR/SbCJXAICCCDweAGSv3lN/u4c+9K0f09Man5OigACCCCAAAIIIIAAAqkmQPL3+BqYEQgggAACCKSwAMlfCm8+l44AAqkkQPJH8pdqd0O4XgQQQAABBBBAAAEEklWA5C+VqnmuFQEEEEAAgTkLkPzNmYwDEEAAgUQUIPmLZvLn9Y7UGlv37BhrbRrUXDPmq3VZ6TqlwpivNuarx5pvyPcXtMsU976/0rD5tao8VVWeyuNwNG7dZL1c5p54JI+hgQACCCCAAAIIIIAAAgjMSYDkLxGrctaMAAIIIIDAggmQ/C0YNSdCAAEEYilA8heV5M/Ra+kqOWxQK+s3rrVeLvNMOqT6fLa3fWqXKa6vX+28PyyEmBwc8E5Pj9QZTXuLdZnPmfYWj9bXCp9vThU+gxFAAAEEEEAAAQQQQAABkr9YVtecGwEEEEAAgbgXIPmL+y1igQgggEA0BEj+Ikz+xttNDZtfM+arzSeOOvqtQfcawiR/Az9+HzRYCOGx2+99f6WxaEPVquzei1+HDqAHAQQQQAABBBBAAAEEEJhNgOQvGlUycyCAAAIIIJC0AiR/Sbu1XBgCCCAQKEDyF2HyN1Jr1KuWtO7aPlyp9U5PB1XgYZK/hzdbggZLH2232juPHNLnZHQePjjjADoRQAABBBBAAAEEEEAAgRkFSP4Cq13aCCCAAAIIIBAkQPIXBMJHBBBAIDkFSP4iTP6EED739JCuvHlHkV61uP3Afv/v+f32rk7z8RLTvt2hNbl2mWK83RTY7+i3dp86VlOYW7Mmz/LNGdfYg8BvaSOAAAIIIIAAAggggAACjxUg+UvOup2rQgABBBBAIEoCJH9RgmQaBBBAIL4FSP4iT/7k8ts5OnL37Kmawtyxpgaps+/qpbrXC3zu4GcBQ5O/qjxVx8EPx9vb5NloIIAAAggggAACCCCAAAJzEiD5i+/6m9UhgAACCCAQYwGSvxhvAKdHAAEEFkaA5C+KyZ9ck8tRn8dub9r2ZuWKpYbcTDkOFEKEJn/yIfIkNBBAAAEEEEAAAQQQQACBOQmQ/C1MHc1ZEEAAAQQQSFABkr8E3TiWjQACCMxNgORvPpK/ORXnDEYAAQQQQAABBBBAAAEEoiJA8je3epjRCCCAAAIIpJgAyV+KbTiXiwACqSpA8kfyF5VbDEyCAAIIIIAAAggggAACMRcg+UvVyp7rRgABBBBA4IkESP6eiIlBCCCAQKILkPyR/MX89gQLQAABBBBAAAEEEEAAgagIkPwleoXO+hFAAAEEEJhXAZK/eeVlcgQQQCBeBEj+SP6icouBSRBAAAEEEEAAAQQQQCDmAiR/8VJpsw4EEEAAAQTiUoDkLy63hUUhgAAC0RYg+SP5i/ntCRaAAAIIIIAAAggggAACUREg+Yt2xcx8CCCAAAIIJJUAyV9SbScXgwACCMwmQPJH8heVWwxMggACCCCAAAIIIIAAAjEXIPmbrfKlHwEEEEAAAQScTifJH/8MEEAAgZQQIPkj+Yv57QkWgAACCCCAAAIIIIAAAlERIPlLiTKei0QAAQQQQOBpBUj+nlaO4xBAAIGEEiD5i23yd3396kHNtagU+Ykyia2zoypPpVctqX3t5cA1Wy9dqMpT6ZSKziOHAvtj3vZMOjSKNOf94ZivhAUggAACCCCAAAIIIBBegOQvocpxFosAAggggMBCC5D8LbQ450MAAQRiIkDyN6/J351jX5r27wlTnMc8+Ws/8J6x4AXN7/+t5/TxMOuM+leDmmtByZ90ivYD+58w+XOO3G8p3lapXqZRpD282TKnFXZ88kH7x+/Lh4TfJpI/GYoGAggggAACCCCAQJwLkPzFpKzmpAgggAACCCSKAMlfouwU60QAAQQiEiD5S/Hkz3q5bKylqfbVlxIu+XONjvZdvfTQ1DrX5M85OqJd+l+Ofqt814bkT6aggQACCCCAAAIIIJDQAiR/EZXHHIwAAggggECyC5D8JfsOc30IIIDAPwVI/qKZ/Hm9I7XG1j07xlqbBjXXjPlqXVa6Tqkw5quN+eqx5hvSTYQHjfU1a/J0SkX7x+/XvV4gve2zcesm6+Uy98Sj0BsNlvOlTW//0Xy8xJivrnx+2d2zp/xjvF7z8ZKqVdl61eKWXW87R0eEEFWrsseaGgJnsJSda965NbBnxvb19asjTP4eNFyv37hWu3yR4YXllvOl0lk8k47Ow5/4F5mT8cuH73omJ+WzR/7Mn3yKWZO/gO2QzyuEuP3FZ6Z9u6SeMNtkOV9atTJLr1rce/6s9LZPe093886tw5Van3s6cELaCCCAAAIIIIAAAgjEiQDJH4U+AggggAACCIQRIPkLg8NXCCCAQPIIkPxFJflz9Fq6Sg4b1Mr6jWutl8s8kw6p8g99mMxts2mVins/XPW53ZYL5zSKNCn5G6kzmvYW6zKfM+0tHq2vFT6ffO/Acr5Uu/RZy/mz/h6fz9HXK4To+/Zi9Ys5k/f6vU6naf+eG29tFkKY9u3uOXNCPtDf827x3XOnA3tmbEeY/NlutVdkPOOPxDye6fGHQzqNdJa2/bsbt26aHn/omXS07t7e8ckH8tnnNfmbbTuEEO5HNp1SMWHuklcihAjdptGGOq1S8eh2p9fpvPnXv0jJn9fl6v/uSuOWN/Q5GZ1HDgVNEjghbQQQQAABBBBAAAEEYiJA8pc8tTpXggACCCCAwDwIkPzNAypTIoAAAvEnQPIXYfI33m5q2PyaMV9tPnE08AWSUp0fGikNVvxsyM389S6Az6dXLZaSP6nHY7ff+/5KY9GGqlXZvRe/ljot50urX1rx6yG//dVYtEF+Ss/Ra9Eo0tyPbH3fXmz581tCiOadRXe++tz/FGCe6mHbzd8OmvXvCJO/9gPvtb33TtDsHrtdo0iT4zFbZ4d2+SJ5zDwlf+G3QwhhPnE09CHI0G3qOPih/AONE+YuKfmTFz81NNBTetJYuLJuXcGDG/VyPw0EEEAAAQQQQAABBGIrQPIXfzU3K0IAAQQQQCCOBEj+4mgzWAoCCCAwfwIkfxEmfyO1Rr1qSeuu7cOVWu908EsgQyMlS9m5+o2vyrcDal99KTD5E0LYbrV3Hjnkf6rs8EFpmOV8qfRIn3yUEMJYmHvvh6tSj5Sx2e9223u69TkZnqmp6+tX129a6xp7UJHxzJO8mjLC5O/Gtj+YT34VuDwhxET3HY0iraYw1yj9KXhBr1osPw05T8lf+O3wTDp02ekPTa1BSw3dppZdb3eVHJaGuR/ZgpI/n9s9Ultt2rdLl50+WP5j0Gx8RAABBBBAAAEEEEAgVgIkf/NXOzMzAggggAACSSBA8pcEm8glIIAAAo8XIPmLMPnzv4DTPT2kK2/eUaRXLW4/sN//e36/vavTfLzEtG93YNk/qP3Z+PILco9BrZSSP0e/tfvUsZrC3Jo1eZZvzrjGHshjpN/5kz9KjRmf+RNC6LLSrZcumI+XtBRvs1660Fi0IejAGT9GmPzN+Myf2z6hUaS5RkdnPOOQTlP76ouhX9069FHn3z4O7Z+txzPpCPqdvzDbYfnmTOOWN0KnCt2mjkP/3X7gPWmkw9orJ38P227e+vQjfU5G49ZNg5prXqczdDZ6EEAAAQQQQAABBBCIlQDJ3+NrYEYggAACCCCQwgIkfym8+Vw6AgikkgDJX+TJn1zVO0dH7p49VVOYO9bUIHX2Xb1U93pB4FN37olH2uW/lx47G6mtln/nrypP1XHww/H2Nnk2uTFj8me9XBb4O3+NRRul8S1/fsuQmzne3tb/j8uG3Ezz8S/leWZs+NzTXperbl2h+eRXXpdLeL3ysAlzV8fBD+2WHrlntoat45eKJb8bNuh8Ho/bZhuu1EojTe8W33xnp5RiTg7ck3//Twhh7+nWLn12amgwaE7rpQt16wr9K3mC/7wul9vmfyBvrLkx9JCg7fBOTxvUSv9vKIb8F7pNY00NBrVyenxcCHH788+k5G/C3FX9Yo755FeTgwMhc9CBAAIIIIAAAggggEDsBUj+Uqma51oRQAABBBCYswDJ35zJOAABBBBIRAGSvygmf3KhL0d9Hru9adublSuWGnIz5ThwrKmhbl1B/aa1pn27jYUrpWf+5EPkSeTGjMmfz+O5879fVK3M0mWnt/zlT877w9J4y9en9aolwudzjtzXKNIeNFyX55mxUb9xrUaRJv+xlJ2Thw1Xav2hWkuT3BOmMXq95vqGV7TLFxnUSss3Z6SRnsnJziOHqvJUOqWipjDX8vXpwBnuHPtSl5WuXaYYqa2W+z1Tky3F23RKhXaZwmO3y/2hDa/LJS9bajy6czt0mPRQphCi79uLdesKZhww4zZZLpyreSWv4c11t7/4m5T8+dzuGQ+nEwEEEEAAAQQQQACBOBEg+UvEqpw1I4AAAgggsGACJH8LRs2JEEAAgVgKkPzNR/IXJ2V/hMvoKjnsfyHnb28ujXC22B7u83iqX1oxpCuP7TI4OwIIIIAAAggggAAC8ypA8hfL6ppzI4AAAgggEPcCJH9xv0UsEAEEEIiGAMkfyd9stx7q1hUEPo0327CE6J8aGugpPZkcKWZCgLNIBBBAAAEEEEAAgZgIkPxFo0pmDgQQQAABBJJWgOQvabeWC0MAAQQCBUj+SP5ickuCkyKAAAIIIIAAAggggEDUBUj+Aqtd2ggggAACCCAQJEDyFwTCRwQQQCA5BUj+SP6ifruBCRFAAAEEEEAAAQQQQCAmAiR/yVm3c1UIIIAAAghESYDkL0qQTIMAAgjEtwDJH8lfTG5JcFIEEEAAAQQQQAABBBCIugDJX3zX36wOAQQQQACBGAuQ/MV4Azg9AgggsDACJH8kf1G/3cCECCCAAAIIIIAAAgggEBMBkr+FqaM5CwIIIIAAAgkqQPKXoBvHshFAAIG5CZD8kfzF5JYEJ0UAAQQQQAABBBBAAIGoC5D8za0eZjQCCCCAAAIpJkDyl2IbzuUigECqCpD8xTb5u75+9aDmWtQL/nie0NbZUZWn0quW1L72cuA6rZcuVOWpdEpF55FDgf0xb3smHRpFmvP+cMxXwgIQQAABBBBAAAEEEAgvQPKXqpU9140AAggggMATCZD8PRETgxBAAIFEFyD5m9fk786xL03794QpzmOe/LUfeM9Y8ILm9//Wc/p4mHVG/atBzbWg5E86RfuB/U+Y/A1qrl1fv1q7TFGpXtZ+4D2P3f7ki+z45IP2j9+Xx4ffJpI/GYoGAggggAACCCCAQJwLkPwleoXO+hFAAAEEEJhXAZK/eeVlcgQQQCBeBEj+Ujz5s14uG2tpqn31pYRL/u6e/b/DlVrn/eGJ7js1r+S1ffDXJ7wL4xwd0S79L0e/VR5P8idT0EAAAQQQQAABBBBIaAGSv3iptFkHAggggAACcSlA8heX28KiEEAAgWgLkPxFM/nzekdqja17doy1Ng1qrhnz1bqsdJ1SYcxXG/PVY803pJsIDxrra9bk6ZSK9o/fr3u9QHrbZ+PWTdbLZe6JR6E3GiznS5ve/qP5eIkxX135/LK7Z0/5x3i95uMlVauy9arFLbvedo6OCCGqVmWPNTUEzmApO9e8c2tgz4zt6+tXR5j8PWi4Xr9xrXb5IsMLyy3nS6WzeCYdnYc/8S8yJ+OXD9/1TE7KZ4/8mT95KiGE5Zsz1fnPB/b42wHbEfjV7S8+M+3bJfWE2SbL+dKqlVl61eLe82elt33ae7qbd24drtT63NOBE9JGAAEEEEAAAQQQQCBOBEj+ol0xMx8CCCCAAAJJJUDyl1TbycUggAACswmQ/EUl+XP0WrpKDhvUyvqNa62XyzyTDqnyD32YzG2zaZWKez9c9bndlgvnNIo0KfkbqTOa9hbrMp8z7S0era8VPp9878ByvlS79FnL+bP+Hp/P0dcrhOj79mL1izmT9/q9Tqdp/54bb20WQpj27e45c0I+0N/zbvHdc6cDe2ZsR5j82W61V2Q844/EPJ7p8YdDOo10lrb9uxu3bpoef+iZdLTu3t7xyQfy2aOb/N38659N7xbLk8+2HUII9yObTqmYMHfJg4UQods02lCnVSoe3e70Op03//oXKfnzulz9311p3PKGPiej88ihoEkCJ6SNAAIIIIAAAggggEBMBEj+Zqt86UcAAQQQQAABp9NJ8sc/AwQQQCAlBEj+Ikz+xttNDZtfM+arzSeOBr5AUqrzQyOlwYqfDbmZv94F8Pn0qsVS8if1eOz2e99faSzaULUqu/fi11Kn5Xxp9Usrfj3kt78aizbIT+k5ei0aRZr7ka3v24stf35LCNG8s+jOV5/7nwLMUz1su/nbQbP+HWHy137gvbb33gma3WO3axRpcjxm6+zQLl8kj4li8jdY/pNBrZwaHhJChN8OIYT5xNHQhyBDt6nj4IfyDzROmLuk5E9e/NTQQE/pSWPhyrp1BQ9u1Mv9NBBAAAEEEEAAAQQQiK0AyV9KlPFcJAIIIIAAAk8rQPL3tHIchwACCCSUAMlfhMnfSK1Rr1rSumv7cKXWOx38EsjQSMlSdq5+46vy7YDaV18KTP6EELZb7Z1HDvmfKjt8UBpmOV8qPdInHyWEMBbm3vvhqtQjZWz2u932nm59ToZnaur6+tX1m9a6xh5UZDzzJK+mjDD5u7HtD+aTXwUuTwgx0X1Ho0irKcw1Sn8KXtCrFstPQ0Yr+btvNBjUyolus3T28NvhmXTostMfmlqDlhq6TS273u4qOSwNcz+yBSV/Prd7pLbatG+XLjt9sPzHoNn4iAACCCCAAAIIIIBArARI/hKqHGexCCCAAAIILLQAyd9Ci3M+BBBAICYCJH8RJn/+F3C6p4d05c07ivSqxe0H9vt/z++3d3Waj5eY9u0OLPsHtT8bX35B7jGolVLy5+i3dp86VlOYW7Mmz/LNGdfYA3mM9Dt/8kepMeMzf0IIXVa69dIF8/GSluJt1ksXGos2BB0448cIk78Zn/lz2yc0ijTX6OiMZxzSaWpffTH0q1uHPur828eh/TP23K+u9Md+//rqzjDbYfnmTOOWN0KnCt2mjkP/3X7gPWmkw9orJ38P227e+vQjfU5G49ZNg5prXqczdDZ6EEAAAQQQQAABBBCIlQDJX0zKak6KAAIIIIBAogiQ/CXKTrFOBBBAICIBkr/Ikz+5qneOjtw9e6qmMHesqUHq7Lt6qe71gsCn7twTj7TLfy89djZSWy3/zl9Vnqrj4Ifj7W3ybHJjxuTPerks8Hf+Gos2SuNb/vyWITdzvL2t/x+XDbmZ5uNfyvPM2PC5p70uV926QvPJr7wul/B65WET5q6Ogx/aLT1yz2wNW8cvFUt+N2zQ+Twet802XKmVRpreLb75zk4pxZwcuCf//p8Qwt7TrV367NTQYNCc1ksX6tYV+lfyuP+GDbrK55fZOn7xulz+PyEPXAZth3d62qBW+n9DMeS/0G0aa2owqJXT4+NCiNuffyYlfxPmruoXc8wnv5ocHAiZgw4EEEAAAQQQQAABBGIvQPIXUXnMwQgggAACCCS7AMlfsu8w14cAAgj8U4DkL4rJn1zoy1Gfx25v2vZm5YqlhtxMOQ4ca2qoW1dQv2mtad9uY+FK6Zk/+RB5ErkxY/Ln83ju/O8XVSuzdNnpLX/5k70iCRkAACAASURBVPP+sDTe8vVpvWqJ8PmcI/c1irQHDdfleWZs1G9cq1GkyX8sZefkYcOVWo0ibaylSe4J0xi9XnN9wyva5YsMaqXlmzPSSM/kZOeRQ1V5Kp1SUVOYa/n6dOAMd459qctK1y5TjNRWy/2eqcmW4m06pUK7TOGx2+X+0EbQyiuW/C50jNQj2fZ9e7FuXcGMY2bcJsuFczWv5DW8ue72F3+Tkj+f2z3j4XQigAACCCCAAAIIIBAnAiR/FPoIIIAAAgggEEaA5C8MDl8hgAACySNA8jcfyV+clP0RLqOr5LD/hZy/vbk0wtlie7jP46l+acWQrjy2y+DsCCCAAAIIIIAAAgjMqwDJX/LU6lwJAggggAAC8yBA8jcPqEyJAAIIxJ8AyR/J32y3HurWFQQ+jTfbsITonxoa6Ck9mRwpZkKAs0gEEEAAAQQQQACBmAiQ/MVfzc2KEEAAAQQQiCMBkr842gyWggACCMyfAMkfyV9MbklwUgQQQAABBBBAAAEEEIi6AMnf/NXOzIwAAggggEASCJD8JcEmcgkIIIDA4wVI/kj+on67gQkRQAABBBBAAAEEEEAgJgIkf4+vgRmBAAIIIIBACguQ/KXw5nPpCCCQSgIkfyR/MbklwUkRQAABBBBAAAEEEEAg6gIkf6lUzXOtCCCAAAIIzFmA5G/OZByAAAIIJKIAyR/JX9RvNzAhAggggAACCCCAAAIIxESA5C8Rq3LWjAACCCCAwIIJkPwtGDUnQgABBGIpQPJH8heTWxKcFAEEEEAAAQQQQAABBKIuQPIXy+qacyOAAAIIIBD3AiR/cb9FLBABBBCIhgDJH8lf1G83MCECCCCAAAIIIIAAAgjERIDkLxpVMnMggAACCCCQtAIkf0m7tVwYAgggEChA8rcwyZ+xcOVg+U9y8X/n2Jem/XvkjzQQQAABBBBAAAEEEEAAgcgFSP4Cq13aCCCAAAIIIBAkQPIXBMJHBBBAIDkFSP4WIPkbrtRW5z8vvF65kif5kyloIIAAAggggAACCCCAQLQESP6Ss27nqhBAAAEEEIiSAMlflCCZBgEEEIhvAZK/aCZ/Xu9IrbF1z46x1qbA0v36+tV9Vy9JPYOaa8Z8tS4rXadUGPPVxnz1WPMN6StbZ0fFkt8N6Stq1uRVrcxq3rnV3tPdvHPrcKXW554OnJA2AggggAACCCCAAAIIIBAqQPIX3/U3q0MAAQQQQCDGAiR/Md4ATo8AAggsjADJX1SSP0evpavksEGtrN+41nq5zDPpkIvw0YY6g1rpnf6X6G7GZ/5snR2aRf/e9v47XpdLCOHotXhdrv7vrjRueUOfk9F55NCEuUuelgYCCCCAAAIIIIAAAgggECRA8rcwdTRnQQABBBBAIEEFSP4SdONYNgIIIDA3AZK/CJO/8XZTw+bXjPlq84mjjn5rUOEthGjc8oblfGlQ/6zJnyJtamggaLAQYmpooKf0pLFwZd26ggc36kMH0IMAAggggAACCCCAAAIIkPzNrR5mNAIIIIAAAikmQPKXYhvO5SKAQKoKkPxFmPyN1Br1qiWtu7YPV2qDHuwTQjxsu6nLSvdMTgbdg5gt+StP/8+gkdJHn9s9Ultt2rdLl50+WP7jjGPoRAABBBBAAAEEEEAAgRQXIPlL1cqe60YAAQQQQOCJBEj+noiJQQgggECiC5D8RZj8CSF87ukhXXnzjiK9anH7gf3+3+3z+aQ7Ds07i8wnjobefTAfLzHt2x3UL/3OX1Dnw7abtz79SJ+T0bh106DmmtfpDBrARwQQQAABBBBAAAEEEEBAEiD5S/QKnfUjgAACCCAwrwIkf/PKy+QIIIBAvAiQ/EWe/Ml3GZyjI3fPnqopzB1rahBCTJi7dEqF22aTB8iNvquX6l4v8Ln/5cf/QpO/CXNX9Ys55pNfTQ7O8ApQeTYaCCCAAAIIIIAAAggggIAQguQvXipt1oEAAggggEBcCpD8xeW2sCgEEEAg2gIkf1FM/uR7DVKkZ9pbfPvzT+XOwIbHbm/a9mbliqWG3EwpJhRChCZ/Prc78CjaCCCAAAIIIIAAAggggEAYAZK/aFfMzIcAAggggEBSCZD8JdV2cjEIIIDAbAIkf/OR/AkhHH292qXPOkfuhynL+QoBBBBAAAEEEEAAAQQQiKIAyd9slS/9CCCAAAIIIOB0Okn++GeAAAIIpIQAyd88JX9jLU0DP/8QxRqeqRBAAAEEEEAAAQQQQACB8AIkfylRxnORCCCAAAIIPK0Ayd/TynEcAgggkFACJH/zlPyFL8j5FgEEEEAAAQQQQAABBBCIugDJX0KV4ywWAQQQQACBhRYg+Vtocc6HAAIIxESA5I/kL+q3G5gQAQQQQAABBBBAAAEEYiJA8heTspqTIoAAAgggkCgCJH+JslOsEwEEEIhIgOSP5C8mtyQ4KQIIIIAAAggggAACCERdgOQvovKYgxFAAAEEEEh2AZK/ZN9hrg8BBBD4pwDJH8lf1G83MCECCCCAAAIIIIAAAgjERIDkj0IfAQQQQAABBMIIkPyFweErBBBAIHkESP5I/mJyS4KTIoAAAggggAACCCCAQNQFSP6Sp1bnShBAAAEEEJgHAZK/eUBlSgQQQCD+BEj+SP6ifruBCRFAAAEEEEAAAQQQQCAmAiR/8VdzsyIEEEAAAQTiSIDkL442g6UggAAC8ydA8jevyd+dY1+a9u+JSc3PSRFAAAEEEEAAAQQQQCDVBEj+5q92ZmYEEEAAAQSSQIDkLwk2kUtAAAEEHi9A8kfyl2p3Q7heBBBAAAEEEEAAAQSSVYDk7/E1MCMQQAABBBBIYQGSvxTefC4dAQRSSYDkL5rJn9c7Umts3bNjrLVpUHPNmK/WZaXrlApjvtqYrx5rviHfX9AuU9z7/krD5teq8lRVeSqPw9G4dZP1cpl74pE8hgYCCCCAAAIIIIAAAgggMCcBkr9Uqua5VgQQQAABBOYsQPI3ZzIOQAABBBJRgOQvKsmfo9fSVXLYoFbWb1xrvVzmmXRI9flsb/vULlNcX7/aeX9YCDE5OOCdnh6pM5r2FusynzPtLR6trxU+35wqfAYjgAACCCCAAAIIIIAAAiR/iViVs2YEEEAAAQQWTIDkb8GoORECCCAQSwGSvwiTv/F2U8Pm14z5avOJo45+a9C9hjDJ38CP3wcNFkJ47PZ7319pLNpQtSq79+LXoQPoQQABBBBAAAEEEEAAAQRmEyD5i2V1zbkRQAABBBCIewGSv7jfIhaIAAIIREOA5C/C5G+k1qhXLWndtX24Uuudng6qwMMkfw9vtgQNlj7abrV3Hjmkz8noPHxwxgF0IoAAAggggAACCCCAAAIzCpD8RaNKZg4EEEAAAQSSVoDkL2m3lgtDAAEEAgVI/iJM/oQQPvf0kK68eUeRXrW4/cB+/+/5/fauTvPxEtO+3aE1uXaZYrzdFNjv6Ld2nzpWU5hbsybP8s0Z19iDwG9pI4AAAggggAACCCCAAAKPFSD5C6x2aSOAAAIIIIBAkADJXxAIHxFAAIHkFCD5izz5k8tv5+jI3bOnagpzx5oapM6+q5fqXi/wuYOfBQxN/qryVB0HPxxvb5Nno4EAAggggAACCCCAAAIIzEmA5C8563auCgEEEEAAgSgJkPxFCZJpEEAAgfgWIPmLYvIn1+Ry1Oex25u2vVm5YqkhN1OOA4UQocmffIg8CQ0EEEAAAQQQQAABBBBAYE4CJH/xXX+zOgQQQAABBGIsQPIX4w3g9AgggMDCCJD8zUfyN6finMEIIIAAAggggAACCCCAQFQESP4Wpo7mLAgggAACCCSoAMlfgm4cy0YAAQTmJkDyR/IXlVsMTIIAAggggAACCCCAAAIxFyD5m1s9zGgEEEAAAQRSTIDkL8U2nMtFAIFUFSD5I/mL+e0JFoAAAggggAACCCCAAAJRESD5S9XKnutGAAEEEEDgiQRI/p6IiUEIIIBAoguQ/JH8ReUWA5MggAACCCCAAAIIIIBAzAVI/hK9Qmf9CCCAAAIIzKsAyd+88jI5AgggEC8CJH8kfzG/PcECEEAAAQQQQAABBBBAICoCJH/xUmmzDgQQQAABBOJSgOQvLreFRSGAAALRFiD5I/mLyi0GJkEAAQQQQAABBBBAAIGYC5D8RbtiZj4EEEAAAQSSSoDkL6m2k4tBAAEEZhMg+SP5i/ntCRaAAAIIIIAAAggggAACUREg+Zut8qUfAQQQQAABBJxOJ8kf/wwQQACBlBAg+Ytt8nd9/epBzbWoFPmJMomts6MqT6VXLal97eXANVsvXajKU+mUis4jhwL7Y972TDo0ijTn/eGYr4QFIIAAAggggAACCCAQXoDkLyXKeC4SAQQQQACBpxUg+XtaOY5DAAEEEkqA5G9ek787x7407d8TpjiPbfJn6/jlxrY/6LLTtcsXNW3f4ui9G2ap0f1qUHMtKPmT5m8/sP8Jkz/nyP2W4m2V6mUaRdrDmy1zWl7HJx+0f/y+fEj4bSL5k6FoIIAAAggggAACCMS5AMlfQpXjLBYBBBBAAIGFFiD5W2hxzocAAgjERIDkL5WTvyF9hfXbMoe1d2p4yLS3uPrFnAW7kRF58ucaHe27eumhqXWuyZ9zdES79L8c/Vb5Ykn+ZAoaCCCAAAIIIIAAAgktQPIXk7KakyKAAAIIIJAoAiR/ibJTrBMBBBCISIDkL5rJn9c7Umts3bNjrLVpUHPNmK/WZaXrlApjvtqYrx5rviHdRHjQWF+zJk+nVLR//H7d6wXS2z4bt26yXi5zTzwKvdFgOV/a9PYfzcdLjPnqyueX3T17yj/G6zUfL6lala1XLW7Z9bZzdEQIUbUqe6ypIXAGS9m55p1bA3tma9tutWsUaVPDQ7MNCN//oOF6/ca12uWLDC8st5wvlQZ7Jh2dhz/xLzIn45cP3/VMTsqTRJ78yaeYNfkL2A75vEKI2198Ztq3S+oJs02W86VVK7P0qsW9589Kb/u093Q379w6XKn1uacDJ6SNAAIIIIAAAggggECcCJD8RVQeczACCCCAAALJLkDyl+w7zPUhgAAC/xQg+YtK8ufotXSVHDaolfUb11ovl3kmHVLlH/owmdtm0yoV93646nO7LRfOaRRpUvI3Umc07S3WZT5n2ls8Wl8rfD753oHlfKl26bOW82f9PT6fo69XCNH37cXqF3Mm7/V7nU7T/j033toshDDt291z5oR8oL/n3eK7504H9szWtl4uM+Rm+jye2QaE6bfdaq/IeMYfiXk80+MPh3QaaXDb/t2NWzdNjz/0TDpad2/v+OQDeZJ5Tf5m2w4hhPuRTadUTJi75JUIIUK3abShTqtUPLrd6XU6b/71L1Ly53W5+r+70rjlDX1ORueRQ0GTBE5IGwEEEEAAAQQQQACBmAiQ/FHoI4AAAggggEAYAZK/MDh8hQACCCSPAMlfhMnfeLupYfNrxny1+cTRwBdISnV+aKQ0WPGzITfz17sAPp9etVhK/qQej91+7/srjUUbqlZl9178Wuq0nC+tfmnFr4f89ldj0Yae08elT45ei0aR5n5k6/v2Ysuf3xJCNO8suvPV5/6nAPNUD9tu/nbQrH87eu/qVYv9ieNT/dd+4L22994JOtRjt2sUaXI8Zuvs0C5fJI+Zp+Qv/HYIIcwnjoY+BBm6TR0HP5R/oHHC3CUlf/Lip4YGekpPGgtX1q0reHCjXu6ngQACCCCAAAIIIIBAbAVI/pKnVudKEEAAAQQQmAcBkr95QGVKBBBAIP4ESP4iTP5Gao161ZLWXduHK7Xe6eCXQIZGSpayc/UbX5VvB9S++lJg8ieEsN1q7zxyyP9U2eGD0jDL+VLpkT75KCGEsTD33g9XpR4pY7Pf7bb3dOtzMjxTU9fXr67ftNY19qAi45nHvprS0W+tWpUdtIzAcz22fWPbH8wnvwoaNtF9R6NIqynMNUp/Cl7QqxbLT0POU/IXfjs8kw5ddvpDU2vQUkO3qWXX210lh6Vh7ke2oOTP53aP1Fab9u3SZacPlv8YNBsfEUAAAQQQQAABBBCIlQDJX/zV3KwIAQQQQACBOBIg+YujzWApCCCAwPwJkPxFmPz5X8Dpnh7SlTfvKNKrFrcf2O//Pb/f3tVpPl5i2rc7sOwf1P5sfPkFucegVkqRm6Pf2n3qWE1hbs2aPMs3Z1xjD+Qx0u/8yR+lxozP/AkhdFnp1ksXzMdLWoq3WS9daCzaEHRg0EdHX2/VKtXAzz8E9c/p44zP/LntExpFmmt0dMaphnSa2ldfDP3q1qGPOv/2cWj/bD2eSUfQ7/yF2Q7LN2cat7wROlXoNnUc+u/2A+9JIx3WXjn5e9h289anH+lzMhq3bhrUXPM6naGz0YMAAggggAACCCCAQKwESP7mr3ZmZgQQQAABBJJAgOQvCTaRS0AAAQQeL0DyF3nyJ1f1ztGRu2dP1RTmjjU1SJ19Vy/VvV4Q+NSde+KRdvnvpcfORmqr5d/5q8pTdRz8cLy9TZ5NbsyY/FkvlwX+zl9j0UZpfMuf3zLkZo63t/X/47IhN9N8/Et5ntCGw9pbtTKr/7srXpdL+hM4ZsLc1XHwQ7ulJ7Bzxrat45eKJb8bNuh8Ho/bZhuu1ErDTO8W33xnp5RiTg7ck3//Twhh7+nWLn12amgwaELrpQt16wq9LldQ/4wfvS6X2+Z/IG+suTH0kKDt8E5PG9TKGd9oGrpNY00NBrVyenxcCHH788+k5G/C3FX9Yo755FeTgwMzrodOBBBAAAEEEEAAAQRiK0Dy9/gamBEIIIAAAgiksADJXwpvPpeOAAKpJEDyF8XkTy7y5ajPY7c3bXuzcsVSQ26mHAeONTXUrSuo37TWtG+3sXCl9MyffIg8idyYMfnzeTx3/veLqpVZuuz0lr/8yXl/WBpv+fq0XrVE+HzOkfsaRdqDhuvyPKGNrqNHNIq0wD/j7SZ52HCl1h+qtTTJPWEao9drrm94Rbt8kUGttHxzRhrpmZzsPHKoKk+lUypqCnMtX58OnOHOsS91WenaZYqR2mq53zM12VK8TadUaJcpPHa73B/a8LpcgSvXKNIe3bkdOkx6KFMI0fftxbp1BTMOmHGbLBfO1byS1/Dmuttf/E1K/nxu94yH04kAAggggAACCCCAQJwIkPylUjXPtSKAAAIIIDBnAZK/OZNxAAIIIJCIAiR/85H8xUnZH+EyukoO+1/I+dubSyOcLbaH+zye6pdWDOnKY7sMzo4AAggggAACCCCAwLwKkPwlYlXOmhFAAAEEEFgwAZK/BaPmRAgggEAsBUj+SP5mu/VQt64g8Gm82YYlRP/U0EBP6cnkSDETApxFIoAAAggggAACCMREgOQvltU150YAAQQQQCDuBUj+4n6LWCACCCAQDQGSP5K/mNyS4KQIIIAAAggggAACCCAQdQGSv2hUycyBAAIIIIBA0gqQ/CXt1nJhCCCAQKAAyR/JX9RvNzAhAggggAACCCCAAAIIxESA5C+w2qWNAAIIIIAAAkECJH9BIHxEAAEEklOA5I/kLya3JDgpAggggAACCCCAAAIIRF2A5C8563auCgEEEEAAgSgJkPxFCZJpEEAAgfgWIPkj+Yv67QYmRAABBBBAAAEEEEAAgZgIkPzFd/3N6hBAAAEEEIixAMlfjDeA0yOAAAILI0DyR/IXk1sSnBQBBBBAAAEEEEAAAQSiLkDytzB1NGdBAAEEEEAgQQVI/hJ041g2AgggMDcBkr/YJn/X168e1FyLesEfzxPaOjuq8lR61ZLa114OXKf10oWqPJVOqeg8ciiwP+Ztz6RDo0hz3h+O+UpYAAIIIIAAAggggAAC4QVI/uZWDzMaAQQQQACBFBMg+UuxDedyEUAgVQVI/uY1+btz7EvT/j1hivPYJn+2jl9ubPuDLjtdu3xR0/Ytjt67YZYa3a8GNdeCkj9p/vYD+58w+RvUXLu+frV2maJSvaz9wHseu/3JV9jxyQftH78vjw+/TSR/MhQNBBBAAAEEEEAAgTgXIPlL1cqe60YAAQQQQOCJBEj+noiJQQgggECiC5D8pXLyN6SvsH5b5rD2Tg0PmfYWV7+Ys2A3MiJP/u6e/b/DlVrn/eGJ7js1r+S1ffDXJ1y8c3REu/S/HP1WeTzJn0xBAwEEEEAAAQQQQCChBUj+Er1CZ/0IIIAAAgjMqwDJ37zyMjkCCCAQLwIkf9FM/rzekVpj654dY61Ng5prxny1Litdp1QY89XGfPVY8w3pJsKDxvqaNXk6paL94/frXi+Q3vbZuHWT9XKZe+JR6I0Gy/nSprf/aD5eYsxXVz6/7O7ZU/4xXq/5eEnVqmy9anHLrredoyNCiKpV2WNNDYEzWMrONe/cGtgzW9t2q12jSJsaHpptQPj+Bw3X6zeu1S5fZHhhueV8qTTYM+noPPyJf5E5Gb98+K5nclKeJPLkT55KCGH55kx1/vOBPf52wHYEfnX7i89M+3ZJPWG2yXK+tGplll61uPf8Weltn/ae7uadW4crtT73dOCEtBFAAAEEEEAAAQQQiBMBkr94qbRZBwIIIIAAAnEpQPIXl9vCohBAAIFoC5D8RSX5c/RaukoOG9TK+o1rrZfLPJMOqfIPfZjMbbNplYp7P1z1ud2WC+c0ijQp+RupM5r2FusynzPtLR6trxU+n3zvwHK+VLv0Wcv5s/4en8/R1yuE6Pv2YvWLOZP3+r1Op2n/nhtvbRZCmPbt7jlzQj7Q3/Nu8d1zpwN7ZmtbL5cZcjN9Hs9sA8L02261V2Q844/EPJ7p8YdDOo00uG3/7satm6bHH3omHa27t3d88oE8SXSTv5t//bPp3WJ58tm2QwjhfmTTKRUT5i55sBAidJtGG+q0SsWj251ep/PmX/8iJX9el6v/uyuNW97Q52R0HjkUNEnghLQRQAABBBBAAAEEEIiJAMlftCtm5kMAAQQQQCCpBEj+kmo7uRgEEEBgNgGSvwiTv/F2U8Pm14z5avOJo4EvkJTq/NBIabDiZ0Nu5q93AXw+vWqxlPxJPR67/d73VxqLNlStyu69+LXUaTlfWv3Sil8P+e2vxqINPaePS58cvRaNIs39yNb37cWWP78lhGjeWXTnq8/9TwHmqR623fztoFn/dvTe1asW+xPHp/qv/cB7be+9E3Sox27XKNLkeMzW2aFdvkgeE8Xkb7D8J4NaKT2tGH47hBDmE0dDH4IM3aaOgx/KP9A4Ye6Skj958VNDAz2lJ42FK+vWFTy4US/300AAAQQQQAABBBBAILYCJH+zVb70I4AAAggggIDT6ST5458BAgggkBICJH8RJn8jtUa9aknrru3DlVrvdPBLIEMjJUvZufqNr8q3A2pffSkw+RNC2G61dx455H+q7PBBaZjlfKn0SJ98lBDCWJh774erUo+Usdnvdtt7uvU5GZ6pqevrV9dvWusae1CR8cxjX03p6LdWrcoOWkbguR7bvrHtD+aTXwUNm+i+o1Gk1RTmGqU/BS/oVYvlpyGjlfzdNxoMauVEt1k6e/jt8Ew6dNnpD02tQUsN3aaWXW93lRyWhrkf2YKSP5/bPVJbbdq3S5edPlj+Y9BsfEQAAQQQQAABBBBAIFYCJH8pUcZzkQgggAACCDytAMnf08pxHAIIIJBQAiR/ESZ//hdwuqeHdOXNO4r0qsXtB/b7f8/vt3d1mo+XmPbtDiz7B7U/G19+Qe4xqJVS5Obot3afOlZTmFuzJs/yzRnX2AN5jPQ7f/JHqTHjM39CCF1WuvXSBfPxkpbibdZLFxqLNgQdGPTR0ddbtUo18PMPQf1z+jjjM39u+4RGkeYaHZ1xqiGdpvbVF0O/unXoo86/fRzaP2PP/epKf+z3r6/uDLMdlm/ONG55I3Sq0G3qOPTf7Qfek0Y6rL1y8vew7eatTz/S52Q0bt00qLnmdTpDZ6MHAQQQQAABBBBAAIFYCZD8JVQ5zmIRQAABBBBYaAGSv4UW53wIIIBATARI/iJP/uSq3jk6cvfsqZrC3LGmBqmz7+qlutcLAp+6c0880i7/vfTY2Uhttfw7f1V5qo6DH463t8mzyY0Zkz/r5bLA3/lrLNoojW/581uG3Mzx9rb+f1w25Gaaj38pzxPacFh7q1Zm9X93xetySX8Cx0yYuzoOfmi39AR2zti2dfxSseR3wwadz+Nx22zDlVppmOnd4pvv7JRSzMmBe/Lv/wkh7D3d2qXPTg0NBk1ovXShbl2h1+UK6g/9OGzQVT6/zNbxy6+LD3ngMmg7vNPTBrVyxjeahm7TWFODQa2cHh8XQtz+/DMp+Zswd1W/mGM++dXk4EDoeuhBAAEEEEAAAQQQQCDmAiR/MSmrOSkCCCCAAAKJIkDylyg7xToRQACBiARI/qKY/Ml1vhz1eez2pm1vVq5YasjNlOPAsaaGunUF9ZvWmvbtNhaulJ75kw+RJ5EbMyZ/Po/nzv9+UbUyS5ed3vKXPznvD0vjLV+f1quWCJ/POXJfo0h70HBdnie00XX0iEaRFvhnvN0kDxuu1GoUaWMtTXJPmMbo9ZrrG17RLl9kUCst35yRRnomJzuPHKrKU+mUiprCXMvXpwNnuHPsS11WunaZYqS2Wu73TE22FG/TKRXaZQqP3S73hzbqN64NXHnFkt+FjpF6JNu+by/WrSuYccyM22S5cK7mlbyGN9fd/uJvUvLnc7tnPJxOBBBAAAEEEEAAAQTiRIDkL6LymIMRQAABBBBIdgGSv2TfYa4PAQQQ+KcAyd98JH9xUvZHuIyuksP+F3L+9ubSCGeL7eE+j6f6pRVDuvLYLoOzI4AAAggggAACCCAwrwIkfxT6CCCAAAIIIBBGgOQvDA5fIYAAAskjQPJH8jfbrYe6dQWBT+PNNiwh+qeGBnpKTyZHipkQ4CwSAQQQQAABBBBAICYCJH/JU6tzJQgggAACCMyDAMnfPKAyJQIIIBB/QjHeawAAIABJREFUAiR/JH8xuSXBSRFAAAEEEEAAAQQQQCDqAiR/8VdzsyIEEEAAAQTiSIDkL442g6UggAAC8ydA8kfyF/XbDUyIAAIIIIAAAggggAACMREg+Zu/2pmZEUAAAQQQSAIBkr8k2EQuAQEEEHi8AMkfyV9MbklwUgQQQAABBBBAAAEEEIi6AMnf42tgRiCAAAIIIJDCAiR/Kbz5XDoCCKSSAMkfyV/UbzcwIQIIIIAAAggggAACCMREgOQvlap5rhUBBBBAAIE5C5D8zZmMAxBAAIFEFCD5I/mLyS0JTooAAggggAACCCCAAAJRFyD5S8SqnDUjgAACCCCwYAIkfwtGzYkQQACBWAqQ/JH8Rf12AxMigAACCCCAAAIIIIBATARI/mJZXXNuBBBAAAEE4l6A5C/ut4gFIoAAAtEQIPlbmOTPWLhysPwnufi/c+xL0/498kcaCCCAAAIIIIAAAggggEDkAiR/0aiSmQMBBBBAAIGkFSD5S9qt5cIQQACBQAGSvwVI/oYrtdX5zwuvV67kSf5kChoIIIAAAggggAACCCAQLQGSv8BqlzYCCCCAAAIIBAmQ/AWB8BEBBBBITgGSv2gmf17vSK2xdc+OsdamwNL9+vrVfVcvST2DmmvGfLUuK12nVBjz1cZ89VjzDekrW2dHxZLfDekratbkVa3Mat651d7T3bxz63Cl1ueeDpyQNgIIIIAAAggggAACCCAQKkDyl5x1O1eFAAIIIIBAlARI/qIEyTQIIIBAfAuQ/EUl+XP0WrpKDhvUyvqNa62XyzyTDrkIH22oM6iV3ul/ie5mfObP1tmhWfTvbe+/43W5hBCOXovX5er/7krjljf0ORmdRw5NmLvkaWkggAACCCCAAAIIIIAAAkECJH/xXX+zOgQQQAABBGIsQPIX4w3g9AgggMDCCJD8RZj8jbebGja/ZsxXm08cdfRbgwpvIUTjljcs50uD+mdN/hRpU0MDQYOFEFNDAz2lJ42FK+vWFTy4UR86gB4EEEAAAQQQQAABBBBAgORvYepozoIAAggggECCCpD8JejGsWwEEEBgbgIkfxEmfyO1Rr1qSeuu7cOV2qAH+4QQD9tu6rLSPZOTQfcgZkv+ytP/M2ik9NHndo/UVpv27dJlpw+W/zjjGDoRQAABBBBAAAEEEEAgxQVI/uZWDzMaAQQQQACBFBMg+UuxDedyEUAgVQVI/iJM/oQQPvf0kK68eUeRXrW4/cB+/+/2+XzSHYfmnUXmE0dD7z6Yj5eY9u0O6pd+5y+o82HbzVuffqTPyWjcumlQc83rdAYN4CMCCCCAAAIIIIAAAgggIAmQ/KVqZc91I4AAAggg8EQCJH9PxMQgBBBAINEFSP4iT/7kuwzO0ZG7Z0/VFOaONTUIISbMXTqlwm2zyQPkRt/VS3WvF/jc//Ljf6HJ34S5q/rFnP/H3r34VVHt/x//V34LgY0IKIgoAiKoiVYqiIiS125miqWiluQlb5hm3jU9ZWrfb5lmmoqmWN5vmaR5zUte8IIgiDBmKq7fo9b3rDNn9gY3sDfsy4uHj9Ps2WvWrHnOwOPxmfdZM6cWf1J62cEjQHVvLCCAAAIIIIAAAggggAAChmGQ/Hl7hc74EUAAAQQQcKsAyZ9beekcAQQQ8BQBkj8XJn/6XoOK9I7kjCr8aLpeaV54cPfu/mFD8jvHbU9JVDGhYRj2yV9VRYV5K5YRQAABBBBAAAEEEEAAgVoESP48pdJmHAgggAACCHikAMmfR54WBoUAAgi4WoDkzx3Jn2EYJRfObYmLLLt2tZaynK8QQAABBBBAAAEEEEAAARcKkPy5umKmPwQQQAABBHxKgOTPp04nB4MAAgjUJEDy56bkr+jg/kvfrXdhDU9XCCCAAAIIIIAAAggggEDtAiR/NVW+rEcAAQQQQACBsrIykj8uAwQQQMAvBEj+3JT81V6Q8y0CCCCAAAIIIIAAAggg4HIBkj+/KOM5SAQQQAABBOorQPJXXzm2QwABBLxKgOSP5M/ltxvoEAEEEEAAAQQQQAABBJpEgOTPq8pxBosAAggggEBjC5D8NbY4+0MAAQSaRIDkj+SvSW5JsFMEEEAAAQQQQAABBBBwuQDJX5OU1ewUAQQQQAABbxEg+fOWM8U4EUAAgQYJkPyR/Ln8dgMdIoAAAggggAACCCCAQJMIkPw1qDxmYwQQQAABBHxdgOTP188wx4cAAgj8I0DyR/LXJLck2CkCCCCAAAIIIIAAAgi4XIDkj0IfAQQQQAABBGoRIPmrBYevEEAAAd8RIPnz8OTv13l5RyaMtr8jcGTC6B0vJm9uG/7Hjm3237IGAQQQQAABBBBAAAEE/FCA5M93anWOBAEEEEAAATcIkPy5AZUuEUAAAc8TIPlrnORvZ2q3y5s36lsPJxfMdZjn6QZ6oabkTzXY2eOFBiZ/lzdt2PvaK4ZhbEtud+dkod5vTet/njzh1OJP7p7+bUuHNroxCwgggAACCCCAAAIIIOAJAiR/nldzMyIEEEAAAQQ8SIDkz4NOBkNBAAEE3CdA8tcIyd8f+Vt+6NHFqKzU9wJI/jQFCwgggAACCCCAAAIIIOAqAZI/99XO9IwAAggggIAPCJD8+cBJ5BAQQACB5wuQ/Lky+ausvFaw89Dot4sO7TeX7j/2T7vw1Vq15vKmDTt7vLC1Y9utCa139nhhZ48Xig7sMwyj4vbtg9lvbuvUfmtizJ5BfW8dO6La/zov7+CoYfuHv7o1ofVPAzKKfztl7tl+zt+D0pITs6bu6J60rVP7Y7njHpSWGoZxYuaUkwvmlv5+wbytHg9z/uxZWIMAAggggAACCCCAgDcKkPw9vwamBQIIIIAAAn4sQPLnxyefQ0cAAX8SIPlzSfJXcu7srx/P2v5Cwk8DMs5/+cWD0hJ9m+D6nt3bX0iovH9frzEMw37OX/n16+fXrrp/65ZRWXl+7aotHaIf3Ps7tPt1Xt6mNi1u7PmxqqLi5Ccf7UpNMc8dtE/+jk54d+/rA+/fuvmgtOTQu8OPT51oGEbxbydPzJqa3zlu76tZF79dp3pW4yn9/cK1gp2GYVzetKHizm09yJrW3zx88E7hiYriO5e+W68bs4AAAggggAACCCCAAAKeIEDy50/VPMeKAAIIIIBAnQVI/upMxgYIIICANwqQ/DUw+bv185E9g/ru7PHCqUXzSn4/b1/t73016+znn1rW2yd//9WgsnJzTJh6696v8/L2Dumvvn1QWrIpOtT8Nj5L8vfg7t1NrZsXn/pVtb994rj5bXxVDx5cK/jhSM6ov6cDTprwX3vkAwIIIIAAAggggAACCHi/AMmfN1bljBkBBBBAAIFGEyD5azRqdoQAAgg0pQDJXwOTv2sFO7clxx56Z/gf+VssE/sMw7h59PDWjm3VIzfNtxHsk7/K+/cL58zcldZ9x4vJO15M3hQdeuvno2rO3+Gx2XrbLQmtr+/ZrT9akr/i305uat18V2rKTvWvV9dtye3MExDvXbl0ZsWSnT27/vhKulFVpfthAQEEEEAAAQQQQAABBHxAgOSvKatr9o0AAggggIDHC5D8efwpYoAIIICAKwRI/hqY/BmGUVVx/8rWzQfefm1bcrufJ0/4+719/w7VDox47dSiefZ3EE4t/PjI+HfN639bMv+ngRn3bxapDjfHhN36+e9X/dnP+Sv+7aTecFda9z/yt+iPFXeLN7VuXn79ul6jFiru3L7wv2v2Dumf3yW+cM6Mu2d+szTgIwIIIIAAAggggAACCPiAAMmfK6pk+kAAAQQQQMBnBUj+fPbUcmAIIICAWYDkr+HJn75BUHb92pkVS3elphTt3/P32/VO/bo1oXXF7f+8PE+3vPDV2t2Zvaoq/vPyvxOzPjw64f+ywLOrVm5q3Vwnf3+/52/vT//3nr+07jpWNAzj8JgRv8yYrLs1DOPIuFGHx4woL7phGEbppYtXtm76u9nYkQdHDbv6Q37VgwfmxiwjgAACCCCAAAIIIICALwmQ/JmrXZYRQAABBBBAwCJA8mcB4SMCCCDgmwIkfy5M/vQtAxXpHckZVfjRdL3SvPDg7t39w4bkd47bnpKoYsKy69f2vTFod7/U/cOGnF21ckt8a538HRw17MDbr22Jb/3TwIy7Z0+b+yk5d3Z3v15b4qL2DOqr1j8oLT2RN23Hi8lbE1rvSk05+69lahKheSuWEUAAAQQQQAABBBBAwCcFSP58s27nqBBAAAEEEHCRAMmfiyDpBgEEEPBsAZI/dyR/hmGUXDi3JS6y7NpVn7yhwEEhgAACCCCAAAIIIICABwqQ/Hl2/c3oEEAAAQQQaGIBkr8mPgHsHgEEEGgcAZI/NyV/RQf3X/puvQfeC2BICCCAAAIIIIAAAggg4KsCJH+NU0ezFwQQQAABBLxUgOTPS08cw0YAAQTqJkDy56bkz1dvJXBcCCCAAAIIIIAAAggg4LECJH91q4dpjQACCCCAgJ8JkPz52QnncBFAwF8FSP5I/jz2tgUDQwABBBBAAAEEEEAAgToJkPz5a2XPcSOAAAIIIOCUAMmfU0w0QgABBLxdgOSP5K9OtxJojAACCCCAAAIIIIAAAh4rQPLn7RU640cAAQQQQMCtAiR/buWlcwQQQMBTBEj+SP489rYFA0MAAQQQQAABBBBAAIE6CZD8eUqlzTgQQAABBBDwSAGSP488LQwKAQQQcLUAyR/JX51uJdAYAQQQQAABBBBAAAEEPFaA5M/VFTP9IYAAAggg4FMCJH8+dTo5GAQQQKAmAZK/hid/vXv3XrVqlccW/84M7O7du/Hx8RcuXHhu4x07dvTu3fu5zWiAAAIIIIAAAggggAACjS9A8ldT5ct6BBBAAAEEECgrKyP54zJAAAEE/EKA5M/Dk7+4uDgdK968eVMIcezYsSVLlgi7n549e6r1y5cvV7cYsrOzhRC7d+82DKNdu3a6H/sbEHl5eTk5OfbrHa7p1avXxo0bHX7FSgQQQAABBBBAAAEEEGhCAZI/vyjjOUgEEEAAAQTqK0DyV185tkMAAQS8SoDkzxuTv8rKyvJ/fubNm9e1a1e1fP/+/SVLliQlJfXo0cMwjNLS0o4dO0ZERDw3+SsrK4uMjDx69KiTdyjWrFnTq1cvJxvTDAEEEEAAAQQQQAABBBpNgOTPq8pxBosAAggggEBjC5D8NbY4+0MAAQSaRIDkzyXJ34wZM9LS0kJDQ/v373/nzp1aCvvyOw9LrxuWf7W0dzjnT7dfuHBhSkqK/rhkyZJ+/fplZGScPXt23bp1kydPjoyMfG7yV1BQ0LJly6qqKt2PYRjr169PSkoKDw9v167d4sWLzV9dvnz5//2//3f9+nXzSpYRQAABBBBAAAEEEECgyQVI/pqkrGanCCCAAAIIeIsAyZ+3nCnGiQACCDRIgOTPJclfUlLS2bNnb9682bVr1wULFtRS8P/w3sPPk6z/qipr3KIeyd+aNWs++uijV1555eeff3Ym+Vu0aFFaWpp5BPfu3QsODi4oKDAM4/bt2/v37zd/axhGWFjYjh07LCv5iAACCCCAAAIIIIAAAk0rQPLXoPKYjRFAAAEEEPB1AZI/Xz/DHB8CCCDwjwDJn0uSv3nz5qkKf/r06dnZ2bVU+0UnjYt7Hlr+1dI+Li6uRYsWkf/8tGrVSr3nT7d3OOevuLi4Q4cOnTt3NgzDmeRvxowZAwcO1H2qJ4WGhISsWLGipvmLsbGx69atM2/CMgIIIIAAAggggAACCDS5AMkfhT4CCCCAAAII1CJA8lcLDl8hgAACviNA8ueS5G/VqlWqyJ8zZ86bb75ZS8F/7+bD4kuG5V8t7ePi4hYuXHjln59ff/3VmeTPMIzJkyd//vnnTiZ/9nP+DMMoKCgYNGhQeHh4ly5dtm3bZhkhc/4sIHxEAAEEEEAAAQQQQMATBEj+fKdW50gQQAABBBBwgwDJnxtQ6RIBBBDwPAGSv0ZO/hrhaZ/mOw7OzPkrKCiIiIiwvOdPdVJZWbls2bLw8HBzn+o9f9euXTOvZBkBBBBAAAEEEEAAAQSaXIDkz/NqbkaEAAIIIICABwmQ/HnQyWAoCCCAgPsESP4aOfm7fsL4fbf1Xy03COrxnj9zb+bkb+XKleWmH92srKwsMjLy6NGjes2tW7e+//77e/fuGYbx2WefxcbG6q8Mw1i7dm3Pnj3Na1hGAAEEEEAAAQQQQAABTxAg+XNf7UzPCCCAAAII+IAAyZ8PnEQOAQEEEHi+AMlfIyd/db0d4MLkT5h+AgMDzSOZPXt2Tk6OXlNUVJSRkREREdGyZcsePXocOHBAf2UYRq9evb799lvzGpYRQAABBBBAAAEEEEDAEwRI/p5fA9MCAQQQQAABPxYg+fPjk8+hI4CAPwmQ/DU8+fOECr+BY7h7925CQsKFCxee28+OHTvS0tKe24wGCCCAAAIIIIAAAggg0PgCJH/+VM1zrAgggAACCNRZgOSvzmRsgAACCHijAMkfyV/j349gjwgggAACCCCAAAIIIOAOAZI/b6zKGTMCCCCAAAKNJkDy12jU7AgBBBBoSgGSP5I/d9xxoE8EEEAAAQQQQAABBBBofAGSv6asrtk3AggggAACHi9A8ufxp4gBIoAAAq4QIPkj+Wv8+xHsEQEEEEAAAQQQQAABBNwhQPLniiqZPhBAAAEEEPBZAZI/nz21HBgCCCBgFiD5I/lzxx0H+kQAAQQQQAABBBBAAIHGFyD5M1e7LCOAAAIIIICARYDkzwLCRwQQQMA3BUj+SP4a/34Ee0QAAQQQQAABBBBAAAF3CJD8+WbdzlEhgAACCCDgIgGSPxdB0g0CCCDg2QIkfyR/7rjjQJ8IIIAAAggggAACCCDQ+AIkf55dfzM6BBBAAAEEmliA5K+JTwC7RwABBBpHgOTPtcnf1KlTx44da67wX3rppXXr1pnX1Gl55MiRcXFxQUFBW7ZsqdOGDhvfvXs3Pj7+woUL6tsHDx4IIc6cOWPf+MaNG7GxsTdu3LD/ijUIIIAAAggggAACCCDgmQIkf41TR7MXBBBAAAEEvFSA5M9LTxzDRgABBOomQPLn7uRv48aNDqO1Ot0pSExMdEnyl5eXl5OTo3ddS/JnGMaMGTMmTJigG7OAAAIIIIAAAggggAACHi5A8le3epjWCCCAAAII+JkAyZ+fnXAOFwEE/FWA5M/dyZ9Lbg24JPkrKyuLjIw8evSoHlLtyd+5c+dCQkLu3Lmj27OAAAIIIIAAAggggAACnixA8uevlT3HjQACCCCAgFMCJH9OMdEIAQQQ8HYBkr+GJ3+///573759w8LC0tPTR40apZ/2OW3atMTERJvNZnna5/Hjx1NTU1u2bBkVFTVs2DB14yA/Pz8mJiYnJyc1NbVr167btm0z31CwT/4OHTrUu3fviIiI6Ojo11577erVq4ZhnD17Nigo6Pr162rby5cvBwYGXrx4UX0sKCho2bJlVVWV7lklfytXrkxMTAwLC5s4caL+Si0kJCR8++23lpV8RAABBBBAAAEEEEAAAc8UIPnz9gqd8SOAAAIIIOBWAZI/t/LSOQIIIOApAiR/DU/+UlNTx4wZU15evn//fpvNppM/dS/A/j1/aWlpeXl5hmGUl5cXFBSoZvn5+UIIlREWFhaGhoaqME99a5/87d27d+vWraWlpWVlZSNGjOjXr59qmZaWtmzZMrW8cOHCzMxMtWwYxqJFi9LS0vRHwzBU8vfaa68VFxcXFhaGhIQcOnTI3GDo0KHTp083r2EZAQQQQAABBBBAAAEEPFaA5M9TKm3GgQACCCCAgEcKkPx55GlhUAgggICrBUj+Gpj8Xb9+XQhx7tw5Vfy/9tprz03+1NTAS5cume8X5OfnN2/eXE/I69GjxxdffKEb2Cd/+ivDMPbu3RseHq7WrF27NiUlRS137tzZPN1wxowZAwcONG+okr99+/aplT179ly7dq25QXZ2tuVwzN+yjAACCCCAAAIIIIAAAh4lQPLn6oqZ/hBAAAEEEPApAZI/nzqdHAwCCCBQkwDJXwOTvxMnTgghysrKVMGfm5tricrs5/ydO3cuOzu77T8/8+bNUxuqp33quwYDBw6cO3eu/mif/F28eHHEiBEdO3aMi4uLiYkJCQlRjUtKSlq0aFFYWPjzzz+Hh4ffu3dPd1LTnL8zZ86oNhkZGStXrtTtDcMYOnTotGnTzGtYRgABBBBAAAEEEEAAAY8VIPmrqfJlPQIIIIAAAgiUlZWR/HEZIIAAAn4hQPLXwORPzfn7448/VPE/YsSI5yZ/+jbBgQMHbDbb8ePHDcPIz8+32Wzl5eXq265du65atUq37NSp06ZNm/RHwzAyMjImTpyoEseffvrJZrPpb999992pU6dOmjQpJydHrzQMo6CgICIiQk8r1E/7rCX5S0hI2LBhg7kTlhFAAAEEEEAAAQQQQMBjBUj+/KKM5yARQAABBBCorwDJX33l2A4BBBDwKgGSvwYmf4ZhpKenz58/3zCMK1euhIeHPzf5W79+fVFRkWEYhYWFNptNPSlUvedvzpw5FRUVW7ZssdlsV65c0TcU3nzzzYkTJ+qPhmF07dp19erVhmFUVFQMGzbMnPzt27cv+p+fgwcPmjcpKyuLjIw8evSoXqme9llT8nf+/PmQkJDbt2/r9iwggAACCCCAAAIIIICAJwuQ/HlVOc5gEUAAAQQQaGwBkr/GFmd/CCCAQJMIkPw1PPm7ePFiv379Xn755f79+w8ZMkQlf1euXIn758dms0VFRcXFxekZeKNHj46Ojg4PD+/YseOaNWvUjYP8/Py4uLgpU6aEhYUlJSVt2bLFfEPhzJkz3bt3Dw0NTU1NVev37duXkpLSu3fvrKysRYsWmZM/wzCSkpI6duxo7kEtz549Ww/juXP+ZsyYMX78ePtOWIMAAggggAACCCCAAAKeKUDy1yRlNTtFAAEEEEDAWwRI/rzlTDFOBBBAoEECJH8NT/5cUvOr5M8lXRmG0a9fP/0GQXOfd+/eTUhIuHDhgnmlw+UbN27ExsbeuHHD4besRAABBBBAAAEEEEAAAQ8UIPlrUHnMxggggAACCPi6AMmfr59hjg8BBBD4R4Dkz/eSv8OHD9tsNv3qQQ+8H8GQEEAAAQQQQAABBBBAwB0CJH8U+ggggAACCCBQiwDJXy04fIUAAgj4jgDJn48lf7169Wrbtu0XX3zhjvsI9IkAAggggAACCCCAAAKeLEDy5zu1OkeCAAIIIICAGwRI/tyASpcIIICA5wmQ/HlI8ufJtw8YGwIIIIAAAggggAACCHiFAMmf59XcjAgBBBBAAAEPEiD586CTwVAQQAAB9wmQ/JH8ecUtDAaJAAIIIIAAAggggAACzxUg+XNf7UzPCCCAAAII+IAAyZ8PnEQOAQEEEHi+AMkfyd9zbx/QAAEEEEAAAQQQQAABBLxCgOTv+TUwLRBAAAEEEPBjAZI/Pz75HDoCCPiTAMkfyZ9X3MJgkAgggAACCCCAAAIIIPBcAZI/f6rmOVYEEEAAAQTqLEDyV2cyNkAAAQS8UYDkj+TvubcPaIAAAggggAACCCCAAAJeIUDy541VOWNGAAEEEECg0QRI/hqNmh0hgAACTSlA8kfy5xW3MBgkAggggAACCCCAAAIIPFeA5K8pq2v2jQACCCCAgMcLkPx5/CligAgggIArBEj+6pH8XeUHAQQQQAABBBBAAAEEEPBIgToVOBV1+Tl8+PCpU6d+//33a9euFRUV3blzp7i4uKSkpLS01L6udEW1Sh8IIIAAAggg4GIBkj8Xg9IdAggg4JkC9hVaaWlpSUlJcXHxnTt3ioqKrl279vvvv586derw4cN1qiFpjAACCCCAAAIIIIAAAggg4MkCdQn+Kkj+PLOoZ1QIIIAAAgg4L0Dy57wVLRFAAAEvFiD58+Q6nLEhgAACCCCAAAIIIIAAAu4TIPnz4mKeoSOAAAIIIFB3AZK/upuxBQIIIOCFAiR/7qui6RkBBBBAAAEEEEAAAQQQ8GQBkj8vLOIZMgIIIIAAAvUXIPmrvx1bIoAAAl4kQPLnyXU4Y0MAAQQQQAABBBBAAAEE3CdA8udFxTtDRQABBBBAoOECJH8NN6QHBBBAwAsESP7cV0XTMwIIIIAAAggggAACCCDgyQIkf15QtDNEBBBAAAEEXCdA8uc6S3pCAAEEPFiA5M+T63DGhgACCCCAAAIIIIAAAgi4T4Dkz4OLdYaGAAIIIICA6wVI/lxvSo8IIICABwqQ/LmviqZnBBBAAAEEEEAAAQQQQMCTBUj+PLBIZ0gIIIAAAgi4T4Dkz3229IwAAgh4kADJnyfX4YwNAQQQQAABBBBAAAEEEHCfAMmfBxXnDAUBBBBAAAH3C5D8ud+YPSCAAAIeIEDy574qmp4RQAABBBBAAAEEEEAAAU8WIPnzgKKcISCAAAIIINB4AiR/jWfNnhBAAIEmFCD58+Q6nLEhgAACCCCAAAIIIIAAAu4TIPlrwmKcXSOAAAIIIND4AiR/jW/OHhFAAIEmECD5c18VTc8IIIAAAggggAACCCCAgCcLkPw1QRHOLhFAAAEEEGg6AZK/prNnzwgggEAjCpD8eXIdztgQQAABBBBAAAEEEEAAAfcJkPw1YvHNrhBAAAEEEGh6AZK/pj8HjAABBBBoBAGSP/dV0fSMAAIIIIAAAggggAACCHiyAMlfIxTd7AIBBBBAAAHPESD585xzwUgQQAABNwqQ/HlyHc7YEEAAAQQQQAABBBBAAAH3CZD8ubHYpmsEEEAAAQQ8T4Dkz/POCSNCAAEE3CBA8ue+KpqeEUAAAQQQQAABBBBAAAFPFiD5c0ORTZcIIIAAAgh4rgDJn+eeG0aGAAIIuFCA5M+T63DGhgACCCCAAAIIIIAAAgi4T4Dkz4XFNV0hgAACCCDg+QIkf55/jhghAggg4AIBkj8eP4v2AAAgAElEQVT3VdH0jAACCCCAAAIIIIAAAgh4sgDJnwuKarpAAAEEEEDAewRI/rznXDFSBBBAoAECJH+eXIczNgQQQAABBBBAAAEEEEDAfQIkfw0optkUAQQQQAAB7xMg+fO+c8aIEUAAgXoIkPy5r4qmZwQQQAABBBBAAAEEEEDAkwVI/upRRLMJAggggAAC3itA8ue9546RI4AAAnUQIPnz5DqcsSGAAAIIIIAAAggggAAC7hMg+atD8UxTBBBAAAEEvF+A5M/7zyFHgAACCDghQPLnviqanhFAAAEEEEAAAQQQQAABTxYg+XOiaKYJAggggAACviNA8uc755IjQQABBGoRIPnz5DqcsSGAAAIIIIAAAggggAAC7hMg+aulWOYrBBBAAAEEfE+A5M/3zilHhAACCDgQIPlzXxVNzwgggAACCCCAAAIIIICAJwuQ/DkoklmFAAIIIICA7wqQ/PnuueXIEEAAAZMAyZ8n1+GMDQEEEEAAAQQQQAABBBBwnwDJn6k4ZhEBBBBAAAHfFyD58/1zzBEigAACZWVlJH/uq6LpGQEEEEAAAQQQQAABBBDwZAGSP24LIIAAAggg4FcCJH9+dbo5WAQQ8F8Bkj9PrsMZGwIIIIAAAggggAACCCDgPgGSP/+9F8CRI4AAAgj4pQDJn1+edg4aAQT8T4Dkz31VdBP2nJWVJYQ4duyYGoPlY2ZmphDixIkTTThCZ3btzDgPHz4shBg0aJDq0PLR4V6EEDabzeFXjbBy0aJFQohFixY1wr5q2oXleqipmTPrLeeoIT0XFxe3b98+KSmpvLxc7XrBggVxcXFBQUFDhgxxZjC1tLGMs5aWnvmVvmhLSkri4uLi4+NLSko8c6guH5Uzv9Qu3ykdIoAAAggg4D8CJH/+dw+AI0YAAQQQ8GsBkj+/Pv0cPAII+I8AyZ9LqvqoqCghxPnz513Sm7mTLVu2fP/99+Y1zixbAhjLx5EjR8bHx58+fdqZrpqwjTNpjSUVOHHiRHx8/JgxY/SwCwsLly5dqj9KKePj45OTk81rGnPZx5I/y7VkudJKSkrmz59/9+7d5wo/ffo0PT3dZrOdO3dONd67d68QIjQ0dOLEiZ999tlze6i9gTPXUu091PVb+wuvrj2Y2+vkT0p58uTJoKCgfv36VVdXm9u4dbl+f4hcMiT7X2qXdEsnCCCAAAIIIKAESP78p/bnSBFAAAEEECgrKyP54zJAAAEE/EKA5M8lNb/7kr/ExMQ33nijroO0BDCWj3XtranaO5PWWJI/+6GOGzcuIiLCfn1TrfGx5M/CaLnSNm7cKIQ4c+aMpZn9x+XLlwshFixYoL9aunSpEGLmzJl6TUMWnLmWGtK//bauvfDMyZ+U8qOPPhJCrFq1yn6/blpTvz9EbhoM3SKAAAIIIICACwVI/vyi7OcgEUAAAQQQ+LcAyd+/JfgvAggg4NMCJH8uKZvdlPwVFxcLIUj+ajlHz03+kpKS/CH5MwyjFiXLV5Z8zvJtQz5aen7vvfecSf7u3bsXHh4eExPz8OFDvfe5c+cKIVasWKHXNGSh4cnf06dPHz165PwYXHvhWZK/ysrKqKioVq1aVVRUOD+keres9x+ieu+RDRFAAAEEEECg0QRI/ny63OfgEEAAAQQQsAqQ/FlF+IwAAgj4pADJn0uKakvyd/z4cSHE6NGj79+//8EHH7Rv3z44ODgmJmb8+PH379/Xe3zy5Mnnn3/es2fP8PBwm83Wvn37N95449ChQ6rByJEjheknPj5eb7h9+/ZXXnklNjY2ODg4Kipq6NCh+pV+qo0lgLF8tKQgAwYMEEJcu3Zt165d6enp4eHhISEhPXr0+OGHH/QepZSPHj365JNPOnbsaLPZYmNjp06dWllZ+c477wghDh48aG5pWb59+/bMmTO7dOmieu7cufO8efPMGY/uPDEx0WaztW3bdty4caWlpZZxSikLCwsHDBgQHh7eokWLnj17btmyxZL8mT9++eWXJr+/F2/cuCGltIQoUsorV67k5OTExcXZbLaIiIiePXt+9tlnjx8/1geyZMkSIcQ333xz4cKFN954IyoqKjg4uGPHjkuXLrU8cfHkyZOjRo1KTEwMCQkJDw9PS0tbv3697kdK+dw5fwcOHBBCvPPOOzdu3BgxYkR0dHRwcHBCQsLs2bP//PNP3VW/fv3UEc2cOTMyMjIpKUl/VVhY+NZbb7Vp0yY4ODg6OvrNN9+0vNNRXQ/Hjx/ftm1br169WrRoER4e3r9/f/NVtHv3boepc48ePcxhnuUc6Svt0qVLFnyLgx6tlHLBggVCiIULF6qVZ86csWzbp08f9dXDhw+XLl3avXv3Fi1ahIaGpqSkLFq0qH7X0nO7OnLkiBAiJyfnzJkzL7/8cnBw8HfffaeGUfslXdOFJ6W8devWBx980KFDB3WlZWRk6D41yJ07d8aOHRsdHW2z2ZKSkhYuXPjkyRP7i3bOnDlOJqO1Xw8rVqywP9F3796NiIgICQm5cOFCLX+INm/enJmZ2bJlS5vNlpCQkJube/PmTX0gUsrg4OC4uLjq6uoVK1Z06dJFHfWQIUP0M11V44KCgoEDB7Zu3TooKCg6OrpPnz7r1q3T/Zh/qfXKAwcOvPrqq9HR0UFBQa1btx44cOCuXbv0t1JKJ/+sXbhwYdSoUepPdMuWLVNSUubPn19ZWWnuimUEEEAAAQR8W4DkzyfLfA4KAQQQQACBmgRI/mqSYT0CCCDgUwIkfy6p5C3J32+//SaEGDx4cEpKSnZ29rfffrtx40aVkQwePFjvMScnRwiRnJz84Ycfzps3b8yYMREREYGBgTt27JBS7tu3Lzc3VwjRrVu31atXf/vtt2rDxYsXCyGio6MnTpw4d+7cYcOGBQQEBAYG7t+/X/esAxi1xvLRkta89tprQohZs2bFxsYuW7YsPz9/4cKFzZs3b9as2S+//KL7HDZsmBCiffv2eXl5c+fOTUpKSktLGzJkiBDC3Ey3Vwt37tyJj48XQmRlZc2ePXvq1KkdOnQQQmRmZj579kw3fvvtt4UQCQkJH3/88ZIlS/r379+5c+fU1FQhhE6tTp061bx584CAgOzs7OXLl0+dOjUyMnLs2LFCiEGDBqmuzCHBhQsX/vWvfwkhmjdvvvqfH3VD3xKiHD9+PCwsrFmzZsOHD1+2bNncuXM7deokhBg4cKBO9VQ/ubm5rVu3njVr1tatW9euXZuQkCCEWLZsmT6KgwcP2v75yc7Onjt37oQJE8LCwoQQn3zyiW7z3OTv2LFjQoj09PS4uLj33ntv8+bNGzZs6N27txDi1Vdf1f0MHTpUCDFnzhyFMH36dPXVpk2bAgMDg4ODx4wZs3jx4pycHJvNFhgYuG3bNr2tuh6mTp3avHnzUaNGzZo1S8UkNptNn8oGJn8VFRWrV6+Oi4sTQsyePXv16tWXLl3SA7AspKSkCCEuXryo1t+7d2/16tWDBg0SQrz55purV6/evn27lNIwDJU7duvWbfbs2R999NFLL70khOjVq5d5Np4z15IzXZ08eVIIMXz48OTk5L59+44fP14lo8+9pGu68M6fPx8dHa0u1wULFkydOrVt27ZCiClTpmiQysrKjh07qgtg6dKl6mocPXp0QECAzWbTzaSU6o9Mr169zCvtl597PVRXV/ft21cIoZBVDyNGjBBCqNcr1vSHSP11atOmzeTJkxcsWKAuyOjo6MuXL+thhIeHR0VFjRs3Li0tbe3atdu2bRs/frz686XTtQ0bNgghoqKiJkyYMG/evEmTJqnLZtq0aaof8y+1WrNq1SohRHh4eG5urv5TIIRYvHix3rUzf9Z+//33Fi1aBAcHDx8+fO7cuTNnzuzZs6cQomfPnk+fPtVdsYAAAggggIBvC5D8+VR5z8EggAACCCDwPAGSv+cJ8T0CCCDgEwIkfy6p5C3Jn560NGfOHN2/YRgRERFCiOLiYinl/fv3mzVrFhMTY57IdfnyZZvNNmDAALWVffry4MGDkJCQoKCg69ev654/++wzFRXoNZaoz/LRkvy98cYbQojIyMiSkhLdw8KFC4UQ77//vlpz9OhRdb9et/nzzz979+4dGBhoDuf05npBvZBs3Lhxek1VVVW7du2EEDqqVFMkY2JiysvLdbPJkyeriV86+VPp1JIlS3Sb69evK1KHyZ+UsqqqSghhedqnOfmrrq5OSkoSQmzcuFF3++jRo5dfflkIoSceKWHzmKWUKqJLTk7WG6p8ztzVqVOnVGZTVVWlmjmZ/Akh5s+fr3v+888/VdB4+PBhtfL1119XQayayKhWFhcXh4aGBgcHazQp5cmTJ4OCglq2bKmfDKmuhxYtWpinXs2ePVsI0a9fP9WV/bWn1js5589hY7XS8r/qSZLt2rWzrLd/2ue0adOEEMOGDdPTMZ8+ffrWW2+ZXxDo5LXkTFenT59WF8/kyZPNY3PmknZ44amLauXKlbq38vJyFYQfOXJErVSzSwcNGqRz8UePHilzS/L37Nmz1q1bN2vWzPxbo3tWC05eDzdu3AgPD2/btq26Qn788UchRP/+/fUY7C+GXbt2CSE6duyo/yBIKdWvSf/+/fUw1K9nZmamPmVSSnX5bd68WTVT8e3p06f1VoZhdO3aNSoq6sGDB1JKS/J37dq14ODg0NBQc5Z87dq1sLCwwMBAnTs682dNXQYq4NR7V2G5nnut17OAAAIIIICArwqQ/PlEWc9BIIAAAggg4KwAyZ+zUrRDAAEEvFqA5M8lNbzD5M9ms+m8R+0lIyNDCKFmDt28eVMIkZiYaJlc8tdff+kh2d9wr6qq2rdvX0FBgW6jHiEohAgLC9MrLVGf5aPD5M8cUkopDx48qCbqqT6nT5+uJm/pXahIyRLOmb9Vy+fPn9++ffu1a9fMX6l5PzoCmTlzppp0aG5z7949c6z44MGDwH9+VBigW06dOrWmOX/OJH8q0TSnd6rn77//3hyD2WerUsonT54EBAQ0a9ZMByRHjhzZsmWLOcqVUqopXKdOnVI9O5n8NWvWTAd1akMVOOm5fSrYGD9+vKaQUi5fvlwIMWHCBPNKKeXo0aOFEPp5m+p60LGualxWVtbsnx+1X/trTzVzefKnqEeNGmUZsyX5e/LkiYqRbt26ZW557do1IYR+Fq4z15KTXan8PiAgoKioyLxHZy5p++Tv119/VRN89URS1ec333wjhBg7dqz6qHh//PFH8x537Nhhjqv1V2oa7s6dO/Uay4KT14OUct26dSrpNwwjPj4+IiLCfNT2F4Oa7Ltp0ybzHqurq9UEX/3/S1CnTGf8qvG8efPMD3dNTEzUT+LVvZn/DFqSP/VsWMvVK6WcOHGiOS9XvyC1/1kbN26c+fdC7f3x48f6N1qPhwUEEEAAAQR8WIDkz6vLeQaPAAIIIIBAXQVI/uoqRnsEEEDAKwVI/lxSxjtM/uzzJPVAvL1790opnz179uKLLwohevfuvW3bNvP7//SQ7G+466+klH/++WdZWdm9e/fu3r0rhAgMDNTfWqI+y0eHyZ+egqM6UY86TEtLUx8HDx4shDA/MVKtV48rNM8w02OwLDx9+rSiokJdb2qqzaJFi8ydW1IEKWVycrKeUFhYWCiEML/NTm27efPmhiR/K1euVO9ys4xW5Ul6sqBK/uzDhtDQUCGE+VGTqp/Hjx/fv39fHWyvXr103OvMe/7UVMLOnTtbhrRp0yYhxNChQ9V6FWx8/fXX5mYqCvrmm2/MK6WU//u//yuEmDhxolqvrgd7cBXbnDx5UkpZ07Xn8uRPnYK8vDzLmC3J37lz54QQcXFxlmZSSnUR3r17V0qpLlT7QzNfS052pZK/2NhY+z2qNbVc0vbJn3pA5ejRoy29XblyRQjRqVMntb558+ZCiDt37pibqWmRljl/UsopU6YIIdauXWtubF528npQm7z22msBAQHqIauWtw/aXwytWrVSLwc1705KOWrUKCHE999/r9ar5E/NctYtP/30U/P/jeDDDz9Us1fXrl1rjht1e0vy9+qrrwohNmzYoBuoBZWhvvHGG+qj+gWp/c+ailSbN2/+8ccfnz59msDPQspHBBBAAAE/ESD588oynkEjgAACCCBQXwGSv/rKsR0CCCDgVQIkfy4p6R0mf6mpqZbOVfK3Z88etf7WrVsDBw5U0+aaNWvWo0eP+fPn37x5U29lf8NdSnn27Nnhw4erPapt1f82MPnTo1J7V8mfPgT1+iv7J+ClpaXpcE4P27zw+PHjFStWdOvWLSgoyDxaIYRO/lTnKhA1b9unTx/duXoCoU4idbMDBw40JPnLy8szhxC628rKSjVa9ZRClfzNnj1bN1ALLVq0MCd/JSUlU6ZMSUhICAgIsBysmujpfPLXp08fy77UxdC7d2+1XgUbltmf6enplv2aP77++utqW5X8HTx40LIL9TjKffv2NWbyp54yumLFCstgLMnf/v37zcdiv6weF+nMteRkVyr5e/nlly0Dc+aStk/+5syZYz9mvUZlzA8fPlRrLFnykydPHM75U4/kNT8V1jJUJ68HtVVJSYkK6vR1onuz/CF6/PixHrnDBf38TNWh5XBWrFhh/qV79OjRpEmTbDab6ioxMfGDDz5Q8bMagCX5U1G65e+VlLKgoEAIoX9x1C+IpZnlz5qU8ssvv9R/S6OiokaMGPHDDz8QAepTzwICCCCAgD8IkPx5VfnOYBFAAAEEEGioAMlfQwXZHgEEEPAKAZI/l9Tz9Uv+1K7/+OOPzz77bMiQISpGat68+e7du9VXlhvuUsozZ86oWUHvvvvuxo0b9+zZc+DAgX379jV8zl/tt8jVTC/9NjKNpqKFWub8qTlACQkJy5cv37lz54F/ft555x375M8yACmlOVZUyZ9OIvUA9u7d25DkT8VO9hPOKioqVA7x5MkT/QKz2pM/wzDUKwP79Onz5Zdf7t69Wx1sSkpKPeb8ZWZm6mNUC+rNarUHGyorzc7Onu/oR7+AUCV/+pWBekfqLB84cKAxk7/c3FwhhGXyopTSkvypiDcmJsbRkf29TkXmKvmr/VpysiuV/Nlfcs5c0vbJ38cffyyESEtLczj+hQsXSilrSv4ePXrkMPn74osvhBAffvihPoOWBSevB7XVkSNHVGKdkJBQWVlp7sryh+jp06fqt2P27NkOD0fn3M4kf2pH9+7d27Bhw6hRo9q0aaM6nzdvnvrKkvylpqYKIX766SfzCKWUO3furEfyJ6V89OjR7t27P/jgg06dOqldZ2VlmV9MaNkRHxFAAAEEEPAxAZI/ryjbGSQCCCCAAAKuEiD5c5Uk/SCAAAIeLUDy55LSvSHJnx7Aw4cP1Xu5oqOj1cvALDfcpZTvvvuu/SvxVEzl1jl/KivasWOHHq1aaN++vZ6WZ/lKSnn16lX1AsKSkhLzt+r5fnrO34ABA4QQ9k9ojIuL050fP37c4dM+1SP+Bg0apPq3hAT2AYyU0hyiqMl8Y8aMMQ9PSqmewRgZGanWOzPnT70prXfv3pYXN3bv3r0eyV+XLl0sQ1JHqudjOZzSNHz4cCHE//zP/1i2tXxUZzM/P9+yXj3tU02es7/2VOMOHToIIc6cOaM+Wp4cq3rWwY/l0aCW3amPKnzVL33UbSzJ34ULF4QQMTExuoHDBWeuJSe7cpj8OXlJ2194a9asEUJkZ2c7HLZeqaa+3b59W6+RUl6/ft180eqvnjvnz8nrQUpZWVmZkJAQHh4+f/58++ff2l8MrVu3FkJcvnxZD8bhgvPJn968urp6165dLVu2DAgIOHfunJTS8kv9+uuvCyHsH2n71VdfCSGGDRumunL4C2I/50/vVy2cPXu2W7duQogvvvjC8hUfEUAAAQQQ8FUBkj+PLtcZHAIIIIAAAq4WIPlztSj9IYAAAh4pQPLnkhq+Hsnf06dPz58//+DBA8sA1Mv/bty44XDelZrEo2Zl6Q3VG+DcmvypiVkLFizQO5VSnj59Wk2RqWnOn5pcpaepqW2rq6s7d+5snvM3depUIcSMGTPMnau0Qyd/5eXlAQEBgYGBFRUV5mZjx45tyJy/X375RQjRsWNHc59Syg0bNgghBg8erNY7k/yppGru3LnmroqKitRjTnUYtmjRIvOxmxurZfWev8DAwLKyMvO36qVuc+bMUSsdBhvqnXnvvPOOeUMp5YMHD9TkRbVe5XMW8PLy8mbNmgUFBT18+FBKqc5d//79zV1VVFSow3Fh8qfGbD+f0pL8PX36NCIiIiAg4MqVK+YhSSnNUM5cS0525TD5c/KStk/+Tp06JYRISEgwnwgp5ePHj80T7FTspGf9qiNdv369w+RPHWwt7/lz8nqQUo4fP16/MlBdHjt37tTO9smfetme/UzN8vJyvZWU0pnkr+ifH/NWUkr1fw5Yv369ffK3dOlSIcT48eMtm+Tk5Aghli1bptY7/AWxJH9lZWW///67pR81d3Ds2LGW9XxEAAEEEEDAVwVI/jyyTGdQCCCAAAIIuEuA5M9dsvSLAAIIeJQAyZ9Lavh6JH+rV68WQkyePNk8gNLS0latWtlstqqqKp2+mJOzkSNHCiFWrVqlt7pw4UKnTp1CQkKEEGorKaVl6pXlo2WeljO3yNWjJjt06KBTikePHmVkZKj91pT8Xbp0SQjRtm1b/aKv6urqKVOmtG3b1hz1qTQlOjpaTw2srq4eMWKEevag7lylnvoZgFLK3377TT37tKY5f3/99ZfKC/UALHP+nj17pp7GaZ5CVFlZ2aVLFyGEnhXnTPL35ZdfmqccSSnv37/fp0+fmJgYIYTOcpxM/ixPcSwpKVHXmH7/mcOzdvfu3dDQ0MDAwMLCQn2FPHz4MDMzMzw8/Pz582qluh5atWpVVFSkm82bN08IMXToULWmqKhICNGqVas///xTt5k1a5bKep1M/hwG1bo3tfD9998LIezTSkvyJ6WcNm2aEOKNN94wz6rcvXt3QEBATk6O6s3Ja8mZrhwmf05e0g4vPPUaRcvsxry8vKCgoHXr1qnxq6Pu37+/Psb79+8nJycHBATYbDYL3bBhw4QQ5ojO0sDJ60EFe5mZmer9dtevXw8NDTX/PtrnneoPQkJCwr179/ROr1+/3qZNm86dO+tft+cmf+fPnxdC9OrVS+XNqqvq6uq+ffsKIdQrJy1z/m7evBkSEtK8eXNzaHf+/PmQkBCbzaanSzr8BTEnf48fP46JiYmIiLh69ao+BP2Y2Y8++si8kmUEEEAAAQR8WIDkz6PKcwaDAAIIIICAuwVI/twtTP8IIICARwiQ/LmkjK9H8ldVVaWeA/niiy9OmTJlzpw548ePV++4mj9/vhrV7du3AwMDAwICsrOzc3JyHjx4oF7pFxoa+uGHH3766afvvvtuWFjYjh071LuvRo4cuW3bNnckf9XV1WoXSUlJc+bMmTt3bnJy8htvvKEyJB3OWTCfPXumsp/evXsvX778448/7tq1a1pamppVEx0dvWzZMvV6toEDBwoh2rRp88EHH0ybNi3ln5/BgwcLIX755RfV7dGjR9WEs0GDBuXl5Y0aNSokJERlUQMHDlRtLCGBlFK9u6tv374TJ05UXVmmT506dSoiIqJZs2Zvv/32kiVLZs6cqZ4yap7040zyV1JS0rJlSyHEyJEjV65cOXXq1Ojo6OnTp6unWfbs2VNFPk4mf3379k1KSurXr9/ChQtnz56tnqo6atQoLeww2JBSbty4MTAw0GazjR49euHChVOmTFGHM27cOL2tOmu5ubmRkZFTpkxZunTpW2+9JYQIDQ3VkZ6+irKysjZt2vTtt9+OHDmye/fu6nGa6omgUkpLimzJmCdOnKie0Zqbm2vOVvVIpJTFxcVCiPbt25tX6gBmxYoVen1VVZUKz7p27Tp79ux58+a9+uqrgYGBkZGR5mE7cy0505XD5M/5S9r+wjt37pz6QzFw4MD58+fn5eWpp6F2795dB+r37t1r166dECIlJWXGjBkTJ05s06bN+++/HxERYUn+nj171rp162bNmt2/f18T2S8893ooLy9v27Zt8+bN//jjD725uuD1o2Xt/xBJKd9//30hRHR09JQpUxYsWDB27Njw8PDAwEA1UU919dzkT0o5btw4IURsbOyECRPmzJkzefLkrl27CiGysrLUQ4/tf6m/+uqrgICA8PDw3NzcpUuXvvfeey1atGjWrJkOUKWUDn9BzMmfmtrbrFmzsLCwkSNHzp49e/r06VlZWQEBAe3atbtz547WYAEBBBBAAAHfFiD584iynEEggAACCCDQWAIkf40lzX4QQACBJhUg+XNJJV+P5E9KWVFRMXv27JSUlObNm9tstvj4+FdffXXv3r3mIX3xxRdt2rSx2WxJSUnq0aBbt2596aWXWrRoERkZOXjwYPUYyQMHDiQkJISEhLz33ns6s9FPmLTkMZa0xplb5FLK8vLy3NzcmJgYNZiFCxc+fvxY9WyeYWYevJSypKQkJyenffv2aqs5c+b8+eef1dXVI0eODA0NjYmJUa/yMgxDRW7BwcFt27YdN27cvXv31EsNDx48qPs8dOhQZmZmWFhYaGhoz549t23bpt67lpGRodrYhwRHjhzp1KlTcHBwbGzs4cOHLXP+1FZXr15VgwwODo6IiMjIyNiwYYOa/6QaOJP8qcefDhgwICoqKiwsrEePHirrunXrVq9evWw2m3p1n5PJ3yuvvKLoFHiHDh0++eSTv/76S1M4PGvq2xMnTrz11ltt2rQJDg6Ojo7u16/fxo0b9YZSShXHXrlyZfPmzT169AgNDQ0PDx8wYICeUKga37t3b+zYsdHR0UFBQbGxsbm5uRUVFdnZ2foRrM9N/m7dupWZmRkSEhIZGfnpp5+ax2BeVtMuLY/xtJ/zJ6V8+PDhkiVLXnzxxdB/fpKSkiZPnqwejas7dPJaem5XDpOHKakAACAASURBVJM/5y9p+wtPSnnz5s0PPvggMTHRZrNFRES8+OKLixcvNgxDD1691W/kyJFRUVH6F+3p06cq+tUTAdWEVyFEWlqaeVuHy7VfDyNGjBBCWGYi6qRfZ2n2f4iklJs2berXr1/Lli1tNlv79u3ffvtt/TdHjcSZ5O/Zs2dr1qxJT0+PiIgIDAyMiYnp06fP119/ra92+19qKeWhQ4eGDh0aFRUVFBQUHR395ptvWnbt8BfEkvxJKfft2zd06FB1kbdq1apbt26ffPJJaWmpQ0lWIoAAAggg4JMCJH9NWo6zcwQQQAABBBpbgOSvscXZHwIIINAkAiR/PlnAN9pBqdeS6cdINtp+fXhH6j1/WVlZPnyMlkNbsGCBEGLx4sWW9XysRWDOnDlCCPOcyFoa8xUCCCCAAAIIIFCTAMlfk5Th7BQBBBBAAIGmEiD5ayp59osAAgg0qgDJX001MOvNAg8fPjx69OiPP/5oWRkWFhYYGKifVWj+luX6Cfhh8ldaWhoWFtauXTvzOwXrp+cnW1VWVkZFRbVq1aqiosJPDpnDRAABBBBAAAE3CZD8NWr5zc4QQAABBBBoagGSv6Y+A+wfAQQQaBQBkj83ldA+1m1JSUlwcHBISMilS5f0oX3yySdCiFdeeUWvYaHhAn6Y/Ekply1bJoRYuHBhwwH9oQf18shVq1b5w8FyjAgggAACCCDgVgGSv0Ypu9kJAggggAACniJA8ucpZ4JxIIAAAm4VIPlzayHtS50vXLhQCBERETFhwoTZs2erN/xFRETwqE/XnmX/TP6ePn3au3dvm82m3vvoWlIf6+3kyZNBQUGZmZnV1dU+dmgcDgIIIIAAAgg0vgDJn1vLbTpHAAEEEEDA0wRI/jztjDAeBBBAwC0CJH+NX1177x63bt2amZkZHR0dHBzcvn37sWPH/vHHH957OJ45cv9M/qSUd+7cad++fVJSUnl5uWeeGk8YVWlpaVxcXHx8fElJiSeMhzEggAACCCCAgLcLkPy5pcymUwQQQAABBDxVgOTPU88M40IAAQRcKkDy5+21OuNHAAEEEEAAAQQQQAABBOonQPLn0vKazhBAAAEEEPB0AZI/Tz9DjA8BBBBwiQDJX/0qZLZCAAEEEEAAAQQQQAABBLxdgOTPJWU1nSCAAAIIIOAtAiR/3nKmGCcCCCDQIAGSP2+v1Rk/AggggAACCCCAAAIIIFA/AZK/BpXTbIwAAggggIC3CZD8edsZY7wIIIBAvQRI/upXIbMVAggggAACCCCAAAIIIODtAiR/9Sqj2QgBBBBAAAFvFSD589Yzx7gRQACBOgmQ/Hl7rc74EUAAAQQQQAABBBBAAIH6CZD81al8pjECCCCAAALeLkDy5+1nkPEjgAACTgmQ/NWvQmYrBBBAAAEEEEAAAQQQQMDbBUj+nCqbaYQAAggggICvCJD8+cqZ5DgQQACBWgVI/ry9Vmf8CCCAAAIIIIAAAggggED9BEj+ai2X+RIBBBBAAAFfEyD587UzyvEggAACDgVI/upXIbMVAggggAACCCCAAAIIIODtAiR/DstkViKAAAIIIOCrAiR/vnpmOS4EEEDgvwRI/ry9Vmf8CCCAAAIIIIAAAggggED9BEj+/qs85gMCCCCAAAK+LkDy5+tnmONDAAEE/hEg+atfhcxWCCCAAAIIIIAAAggggIC3C5D8cWMAAQQQQAABvxIg+fOr083BIoCA/wqQ/Hl7rc74EUAAAQQQQAABBBBAAIH6CZD8+e+9AI4cAQQQQMAvBUj+/PK0c9AIIOB/AiR/9auQ2QoBBBBAAAEEEEAAAQQQ8HYBkj//uwfAESOAAAII+LUAyZ9fn34OHgEE/EeA5M/ba3XGjwACCCCAAAIIIIAAAgjUT4Dkz39qf44UAQQQQACBsrIykj8uAwQQQMAvBEj+6lchsxUCCCCAAAIIIIAAAggg4O0CJH9+UfZzkAgggAACCPxbgOTv3xL8FwEEEPBpAZI/b6/VGT8CCCCAAAIIIIAAAgggUD8Bkj+fLvc5OAQQQAABBKwCJH9WET4jgAACPilA8le/CpmtEEAAAQQQQAABBBBAAAFvFyD588kyn4NCAAEEEECgJgGSv5pkWI8AAgj4lADJn7fX6owfAQQQQAABBBBAAAEEEKifAMmfT5X3HAwCCCCAAALPEyD5e54Q3yOAAAI+IUDyV78Kma0QQAABBBBAAAEEEEAAAW8XIPnzibKeg0AAAQQQQMBZAZI/Z6VohwACCHi1AMmft9fqjB8BBBBAAAEEEEAAAQQQqJ8AyZ9Xl/MMHgEEEEAAgboKkPzVVYz2CCCAgFcKkPzVr0JmKwQQQAABBBBAAAEEEEDA2wVI/ryyjGfQCCCAAAII1FeA5K++cmyHAAIIeJUAyZ+31+qMHwEEEEAAAQQQQAABBBConwDJn1eV7wwWAQQQQACBhgqQ/DVUkO0RQAABrxAg+atfhWzeKiIiolmzZoGmn06dOpkbuHC5sLDwt99+c6bDkpKS7du3q5adOnXavXu3M1uZ2+zduzc6Ojo9Pd28Ui/fuHFDCPHkyRO9oL9yfmHs2LFz5851vn29W8bHxx84cKAhQ633rtkQAQQQQAABBBBAAAGPFSD584qynUEigAACCCDgKgGSP1dJ0g8CCCDg0QIkfw0vwiMiIvbs2dPwfpzpYcKECV9//bUzLTdt2vTOO++olvVL/iZNmjR+/Pia9qVTNL1QU8ta1ldUVFRVVdXSwFVfkfy5SpJ+EEAAAQQQQAABBHxJgOTPo8t1BocAAggggICrBUj+XC1KfwgggIBHCpD8Nbxuryn5GzVqVG5urup/zJgxOTk5Uso7d+4MGzYsOTm5S5cuH3300ZMnT6SUjx49mjx5clxcXNu2badNm1ZdXX3p0iUhhB5b9+7d8/Pzly9f3rx585iYmOnTp0spv/nmm65du3bq1KlPnz6nT5/WjaWUhw8fjoqKioiI6NOnj5SyU6dOn332WWpqamRkZHp6+p07d9ROp0+fnpyc3KlTp7fffvvevXvmHpYuXdqyZcvIyMisrCwp5ZEjR3r06JGUlNS5c+fPP/9cSqkDP73gsFl8fPzx48ellJWVlUFBQWpbKeULL7ywd+9ePedv3LhxM2fOfPvtt9PT0zt16nTkyBEpZUlJyZAhQ+Li4tLT09euXZuQkGAeoUM3KeWJEyfS0tKSk5O7deu2efNmtYl98te9e/fVq1dbOuQjAggggAACCCCAAAJ+JUDy55FlOoNCAAEEEEDAXQIkf+6SpV8EEEDAowRI/hpe2NeU/N2/f799+/a//PLLoUOH4uPjHzx4IKXMysqaOnXqs2fPDMNIS0tbu3atlHL+/PkDBgx49OhRZWVlt27d1q5d6zD5k1L26dNHzfk7duxYq1atrl69KqXcvn17+/bt//rrL/OxzJ071zznLysrq6Ki4vHjx3369Pn444+llAsWLOjdu7eacjdlypQRI0aYN5dSTpw4ccaMGVLK8vLyiIiIvXv3Silv3boVHR1tfnKmTv4cNpswYcLSpUullLt37+7Tp8+bb76pIr3Q0NBHjx7p5G/ixIlxcXGlpaVSymXLlmVkZEgpc3NzX3/99erq6vv377/88ssdO3a0jNDeraKiIjIyUj3m9Nq1ay1btrxw4YKU0j75O3DggNKz9MlHBBBAAAEEEEAAAQT8R4Dkz6PKcwaDAAIIIICAuwVI/twtTP8IIICARwiQ/DW8qo+IiAgODraZflasWKG63bNnT0pKSufOnQ8ePCilLCsrE0Lcvn1bffvNN99kZmZKKbt27fr999+rlRUVFX/++edzk7/JkydPmDBBDz4uLu7w4cP6o5TSkvxt3LhRffvRRx+NGTNGSpmSkrJp0ya18tq1a4GBgWoCou5EJ3/btm1LSkrS63Nycj788EMd+OkFh822bds2ePBgKeW0adO+++67+Pj4Z8+ebd26Va00J3/vvfee2sW+ffvi4uKklElJSfpVhStXrrRP/uzdtm/fbh7q6NGj58+f7zD504fDAgIIIIAAAggggAACfitA8ucRZTmDQAABBBBAoLEESP4aS5r9IIAAAk0qQPLX8CK/pjl/queuXbt269ZNLV+4cEEIEf/vn9jY2O7du0spo6Ki9u/fbx7Jc5O/4cOHR0RE/Lun+KioKJ0dqn4syd/u3bst61u3bt2mTRvdQ0RExK1bt8xj0Mnf6tWr09PT9VezZs3Kzs7WgZ9ecNjs/v37rVq1evr0affu3YuLiwcOHHj27Nnc3Fz12E9z8qfmF0opDxw4EBsbK6WMjIzUceb27dvtkz97tzVr1thsNn1Qbdq0mTRpEsmfPncsIIAAAggggAACCCBgFiD5a9JynJ0jgAACCCDQ2AIkf40tzv4QQACBJhEg+TPXvfVbriX5+5//+Z+srKz09PSvvvpKSnn//n0hRFlZmWVHL7zwwnfffadWlpSU3L59+8qVK0KIZ8+eqZUdOnTIz883P+1z6tSpkydPtvRj/vjc5K9bt256Rp15Q72sk7/8/Hxz6paTkzNt2jQd+OkFh82klKmpqXv37u3cubOUcvHixZ9//nnnzp0vX74spaw9+UtMTPzhhx/UeP71r3+Zx6BW2rvt2LEjJSVFH4JesH/ap/6KBQQQQAABBBBAAAEE/FaA5K9JynB2igACCCCAQFMJkPw1lTz7RQABBBpVgOSv4UV+TcnftWvXoqOjr127dvHixaioqOvXr6v3/M2ePVtKWV1dvXTpUvUQzrlz5/bp08f456dXr16rVq2qqqoKCgo6f/68lPLw4cNBQUEq+evfv/+nn34qpTx27FibNm1u3Lghpbx+/frw4cMNwzAfy4IFC4YOHarWdOrUyX7O38KFC7OystRWP/7447Rp08ybm9/zd//+/ZYtW+7Zs0dKWVRU1Lp162PHjunATy84bCalnDdvXkZGxsSJE9WwMzIyOnTooPZVe/I3evTo7OzsZ8+eVVRUpKam2id/9m4VFRVRUVE//vijlNIwjAkTJpw+fdrhnL9Dhw6pM2I5aj4igAACCCCAAAIIIOA/AiR/jVp+szMEEEAAAQSaWoDkr6nPAPtHAAEEGkWA5K/hVX1ERESzZs0C//vn5s2bGRkZ//rXv1T/CxYs6Nu3b3V19Z07d4YNG5aYmBgfH//WW2+VlJRIKR8+fJibm9u+ffu2bdtOmjTp6dOnUspPP/00OTk5Kytr1qxZmZmZW7ZskVKuXbs2NDR05MiRUspvvvnmhRde6NixY5cuXb799lvLgZw8eTIqKiouLu7p06cOk79Hjx7NmDEjKSkpMTExLS3t5MmTlh70nD8p5dGjR3v06JGcnPzCCy+o+Ys68NMLDptJKX/++WchhHoY6aNHj0JCQnJzc9W+ak/+ioqKMjIy4uLisrKyvvjiC/ML/NTmDt1OnDiRlpbWsWPHDh065OXlKUz7OX/du3dfvXq15ZD5iAACCCCAAAIIIICAXwmQ/DVK2c1OEEAAAQQQ8BQBkj9POROMAwEEEHCrAMmfXxX2XnewKreTUm7evLlXr15eN34GjAACCCCAAAIIIICAJwuQ/Lm13KZzBBBAAAEEPE2A5M/TzgjjQQABBNwiQPLnyXW4n49t6dKlmZmZjx49+uuvvwYOHDhz5kw/B+HwEUAAAQQQQAABBBBwrQDJn1vKbDpFAAEEEEDAUwVI/jz1zDAuBBBAwKUCJH+urZzpzYUCVVVVo0aNio2NjYuLGz169IMHD1zYOV0hgAACCCCAAAIIIIAAyZ9Ly2s6QwABBBBAwNMFSP48/QwxPgQQQMAlAiR/VPsIIIAAAggggAACCCCAgH8KkPy5pKymEwQQQAABBLxFgOTPW84U40QAAQQaJEDy558VPkeNAAIIIIAAAggggAACCJD8NaicZmMEEEAAAQS8TYDkz9vOGONFAAEE6iVA8ke1jwACCCCAAAIIIIAAAgj4pwDJX73KaDZCAAEEEEDAWwVI/rz1zDFuBBBAoE4CJH/+WeFz1AgggAACCCCAAAIIIIAAyV+dymcaI4AAAggg4O0CJH/efgYZPwIIIOCUAMkf1T4CCCCAAAIIIIAAAggg4J8CJH9Olc00QgABBBBAwFcESP585UxyHAgggECtAiR//lnhc9QIIIAAAggggAACCCCAAMlfreUyXyKAAAIIIOBrAiR/vnZGOR4EEEDAoQDJH9U+AggggAACCCCAAAIIIOCfAiR/DstkViKAAAIIIOCrAiR/vnpmOS4EEEDgvwRI/vyzwueoEUAAAQQQQAABBBBAAAGSv/8qj/mAAAIIIICArwuQ/Pn6Geb4EEAAgX8ESP6o9hFAAAEEEEAAAQQQQAAB/xQg+ePGAAIIIIAAAn4lQPLnV6ebg0UAAf8VIPnzzwqfo0YAAQQQQAABBBBAAAEESP78914AR44AAggg4JcCJH9+edo5aAQQ8D8Bkj+qfQQQQAABBBBAAAEEEEDAPwVI/vzvHgBHjAACCCDg1wIkf359+jl4BBDwHwGSP/+s8DlqBBBAAAEEEEAAAQQQQIDkz39qf44UAQQQQACBsrIykj8uAwQQQMAvBEj+qPYRQAABBBBAAAEEEEAAAf8UIPnzi7Kfg0QAAQQQQODfAiR//5bgvwgggIBPC5D8+WeFz1EjgAACCCCAAAIIIIAAAiR/Pl3uc3AIIIAAAghYBUj+rCJ8RgABBHxSgOSPah8BBBBAAAEEEEAAAQQQ8E8Bkj+fLPM5KAQQQAABBGoSIPmrSYb1CCCAgE8JkPz5Z4XPUSOAAAIIIIAAAggggAACJH8+Vd5zMAgggAACCDxPgOTveUJ8jwACCPiEAMkf1T4CCCCAAAIIIIAAAggg4J8CJH8+UdZzEAgggAACCDgrQPLnrBTtEEAAAa8WIPnzzwqfo0YAAQQQQAABBBBAAAEESP68upxn8AgggAACCNRVgOSvrmK0RwABBLxSgOSPah8BBBBAAAEEEEAAAQQQ8E8Bkj+vLOMZNAIIIIAAAvUVIPmrrxzbIYAAAl4lQPLnnxU+R40AAggggAACCCCAAAIIkPx5VfnOYBFAAAEEEGioAMlfQwXZHgEEEPAKAZK/ulb7V/lBAAEEEEAAAQQQQAABBDxVoE4FDsmfV5TtDBIBBBBAAAFXCZD8uUqSfhBAAAGPFiD5q1NhLKW8evWqwQ8CCCCAAAIIIIAAAggg4HkCV69erVOBQ/Ln0eU6g0MAAQQQQMDVAiR/rhalPwQQQMAjBUj+6lQYk/x53s0NRoQAAggggAACCCCAAAL/J0Dy55FlN4NCAAEEEEDAUwRI/jzlTDAOBBBAwK0CJH8kf9wmQQABBBBAAAEEEEAAAd8QIPlza/lM5wgggAACCHi7AMmft59Bxo8AAgg4JUDyR/LnG/c4OAoEEEAAAQQQQAABBBAg+XOqDKYRAggggAAC/ipA8uevZ57jRgABPxMg+SP54/4IAggggAACCCCAAAII+IYAyZ+fFfQcLgIIIIAAAnUTIPmrmxetEUAAAS8VIPkj+fONexwcBQIIIIAAAggggAACCJD8eWlhzrARQAABBBBoHAGSv8ZxZi8IIIBAEwuQ/JH8cX8EAQQQQAABBBBAAAEEfEOA5K+JC2x2jwACCCCAgGcLkPx59vlhdAgggICLBEj+SP584x4HR4EAAggggAACCCCAAAIkfy4qlOkGAQQQQAAB3xQg+fPN88pRIYAAAhYBn0n+bt269f333//www83b958bph34cKFnTt3btq0qaqq6rmNLQ2uXr3qkhsKL7300rp16xrYVX5+fmJiYgM7cX7zkSNHxsXFBQUFbdmyxbxVYmJibGysEKK4uNi8vvbl5cuX9+vXr/Y2TfXtypUr4+LiwsLCJk2a5MwYpk+fPnLkSGda1qNNTYOp6XTUvosjR44kJyeHh4cPHjzYMIxjx47FxcVFRUWlpKTUvmHt3+bl5Q0fPrz2NnyLAAIIIIAAAggg4G4Bkj9LwctHBBBAAAEEEDALkPyZNVhGAAEEfFbAl5K/Xbt2WVK6Wj5WV1e7Nvlb+6Lx/dsPna/kN27ceObMGefbO2x58eLFhseHvXv3XrNmjcP+Ha5MTEy0JH+GYVy5cqWuyV9hYeHWrVsd7qKBK3fv3t2uXbsGdmIYxtixYz0h+VMHUtNgHJ6OWo79lVdemT9/vqXBunXrSP4sJnxEAAEEEEAAAQS8UYDkz2dLdw4MAQQQQAABVwiQ/LlCkT4QQAABjxcg+aslHXT4VU1z/uqa/HnOfYSmSv7cJ0DyV4ttUlJSfn6+pQHJnwWEjwgggAACCCCAgJcKkPx5fAnOABFAAAEEEGhKAZK/ptRn3wgggECjCZD8WeK906dP79mzx7LS/NHJ5K+kpEQIMXny5PT09C5dunz88cf63sG0adMSExNtNpt5ul5+fn5MTExOTk5qamrXrl23bdum2ztc+OOPPxITE2NiYixP++zdu/fUqVP79++fmJjYv3//O3fuqM2PHz+emprasmXLqKioYcOGqZUTJ05MTEwMCQlp3bp14j8/9+7dMwzj1q1bQ4YMad26dURERGpq6qFDh8xjcDjJrE5z/tauXZuYmBgVFWV+2ufu3bujo6P1joQQJ0+eNAzDoUxlZWW7du02b96s2yclJX399ddnz55NTExs27ZtYGCgOqKFCxeqNiUlJbm5ue3bt2/duvW7775bUlKit23RosXatWtTU1Pj/vm5e/eu+sp+ml1NMtOnTx86dOiAAQPCwsJ69uz566+/6s5rWigoKOjZs2d4eHjbtm2XLFmimv3+++9DhgyJioqKi4tbtGiReVv7wahvHZ4O84Z6efjw4YmJicHBweqyGTFihP7KYfKXm5urHnnauXPntWvX6sbr169PSkoKDw9v167d4sWL1fq8vLzXX389Ozs7NDQ0OTn5l19+0e1ZQAABBBBAAAEEEGg0AZK/Riul2RECCCCAAALeKEDy541njTEjgAACdRYg+TOnelLK48ePb9myxbLS/LFOyd/YsWMNwyguLu7QoYM5pjIMw/Kev/z8fCGEygILCwtDQ0Nr2pH5roH9e/569+7dvXv30tLSysrKPn36LFiwQLVPS0vLy8szDKO8vLygoMDcif2cv2vXrq1cufLmzZuVlZUrV64MDw8vLS3VmziMmuqU/KmuLO/5qyX5cygza9asoUOHqq4OHz4cFhamB+lwzt+IESMyMzOLiopKSkpef/31cePG6SNq0aLFSy+9dOXKFcMwLl68WF5err6yD9tqkpk+fXqzZs0KCgoqKipmzpyZlJRUWVmp+7dfOHr0aEhIyKZNmx48eFBUVLRx40Z1ajp06DB16tTy8vKLFy927Nhx/fr1elv7waivHJ4OvZX9QmJiopNz/hYvXnz+/HnDMI4cORISErJ//37DMO7duxccHKwuodu3b6uVhmHk5eWFhIQUFBSUl5e/++67WVlZ9rtmDQIIIIAAAggggIC7BUj+6lwSswECCCCAAAL+JEDy509nm2NFAAE/FiD5M6d6zizXFMh9lf5we85/Cnk150/Plps2bdrbb7/9n68dJX/NmzevqqpSbXr06PHFF1+Y2ztcdpj86blis2bNys7OVhump6ePGjXq0qVL9v3YJ3/mNpWVlYGBgSdOnNArHUZNbk3+HMqcP3/eZrMVFRUZhvH++++rkFUN0j75Ky4uFkIUFhaqBseOHQsPD9dH1KJFi6+++kp/1As1hW2qgVlm+vTp6enpan1JSUlAQIASu1/8cPOw//uXP0Z3/PcbBPWp0Wu3bt0aGRmpI8MlS5a8+uqr+tuaBuPwdBRM/s9+iy/rPv5ecD75M2+WkZGxfPlywzBKS0tDQkJWrFihp5OqZnl5eZmZmWp5586dsbGx5s1ZRgABBBBAAAEEEGgcAZI/Py7uOXQEEEAAAQSeL0Dy93wjWiCAAAI+IEDy50zaZ25TU/K36c2HP838Tzmvkr8zZ86oVYsXL87IyPjP146Sv5iYGN1g4MCBc+fO1R9rWnCY/K1atUq1nzNnzptvvqmWz507l52d3fafn3nz5pk7tE/+ysvLp06d2qlTJ/X0y4CAgCNHjuhNHEZNbk3+apLp06fPp59+WlFRERkZeeDAAT1C++SvsLBQCJFk+omMjNQP/GzRooWeu6Y7MYy/87lJkyaZ19QkM336dP0MVcMwwsLCdu3a9fcMuZsPP0/6v39f9vhPT/37958zZ85/Pv+ztGLFipCQED3G+Ph4naU5HIza3OHpWP+Kofd7+9xD846cT/5Wr1798ssvx8fHx8XFNW/eXCfKBQUFgwYNCg8P79Kli34sbV5e3vDhw9WO9u7dGxkZad4pywgggAACCCCAAAKNI0Dy5wNFOoeAAAIIIICA+wRI/txnS88IIICABwmQ/JlTPWeWa0r+7v7xd8yj63mV/P30009qTW5urs5F1Br7p33abDb9nMmuXbvqAE/3ab/gfPKntz1w4IDNZjt+/Lhe06dPnzVr/n97d/faRLPAcfxviWiDpjGiVStRsAQsGAgVsdKKFYpQUK+EFotYfLsQFalgCCh6cc6FF4JoAy1CoQoeEmqsSF4MSZ/EJGbbzUtpG+bcengcWPZsXlqfNjZpvns1u9mdznymN7M/ZvZf2qkQ4uHDhz09PZlMRgixvLy8c+dOn8+n3eBwON68eaOdykImkzGZTIqiGK7XODXs9vnx48d9+/bJ++USPe07f9VkXr586XQ6vV5vV1eX/g/NzMwcPnxYf0VWmEql9Be1ssVi0XdQuz46Onr9+nXttIZM+Zo/bX2h/nGtXG3Nn6Ej2v1CiPLGyF8rDof+QUO5YvL3+vXrEydO6O/88OGDzWbTenHmzBnti4nytlKp5PF4tKWTJH96PcoIIIAAAggggMBWCZD8NdBkm6YggAACCCDQeAIkf403JrQIAQQQiIp1OgAABsZJREFUqIMAyZ8h7QuFQjMzM4aL+tNqyd+70f/+57Ex+Tt//nw+n49EIgcOHJDfctNeAZQnfyaT6cGDBysrK16v12w2y8/OafdXLKw/+Xv16pXcGPPLly9ms/nbt29ahZcvXx4dHdVOhRA3bty4cuWKvOLxeEwmkz4YGxoaMuRh8s7yPurrLC8bkr90Ot3W1hYKhYQQT58+NZlMWvJXTaZYLFqt1u7u7vHxcX39kUikra0tmUzqL166dGloaCidTgshYrGYfjiqJX/Pnj1zOp1aHFtDxvCdP4fDoW3cqm+DVvb7/Waz+e3bt6urq4qiyCR1aWnp2LFjjx8/XlpaWl1d/fTp0/v377VHyhsjf6o2HNqDhkLF5O/r16+7d+/WbwY7MTFx9OjR5eVl+Z0/s9kskz9FUSYmJorFohDi+fPn2q6eJH8GZ04RQAABBBBAAIEtESD5q8OkmSoRQAABBBDYPgIkf9tnLOkJAgggUEOA5E+f6v38+TMQCHi9XsNF/Wm15O/fTjFx2Zj8jY+Pd/w67t+/L2f+iURCbqFpNpv3799vt9uHh//+PODk5KTdbr9582Z7e3tXV5fX6639puDWrVt2u72jo2PXrl2ywmAwKIQ4ffq0tlhQv9vn1atXOzo6rFbr8ePHDSv8Pn/+3N3dffDgwc7OTpnofP/+va+vz+l0njt3zuPxGIKxcDh88uTJPXv2nDp1St9Ir9d75MgRi8Vy584d/fVqZUPyJ4Rwu912u72/v//Fixf65K+GzPDw8I4dO/766/+/ZSfE2NiY7JG2tWk+nx8bG7Pb7VL4yZMnWsMMHdSuFwqFwcHB9vZ2i8WiqqoQoprM3bt3BwcHBwYGLBZLT0+PHAutnoqFd+/euVwuq9V66NAht9st74lGoxcvXpQj5XK5pqamtGfLGyN/qjYc2oOGQsXkTwhx7949m81msVgmJyeFEKVSaWRkxOFw9Pf3X7t27ezZszL5+/HjR29v7969e202m8vl0jZZJfkzOHOKAAIIIIAAAghsiQDJX43JLz8hgAACCCCAAMkf/wMIIIBASwjUTv6y2WwqlYrFYsFg0Ofz6QOwRiurqjo1NTU9Pa0oyppti8Vi09PTMuFY82bDDdWSP8PEXu72GY/HDderncrkr9qv2/K62+2+cOHCml2rLfPo0aO+vr41K+EGBBBAAAEEEEAAAQRaQWAjyV9PpWNFd/h8vmAwGIvFUqlUNptdXFxUVTWfzxcKhfJ5ZUtMp+kkAggggAACzSZA8tdsI0Z7EUAAgX8kUD5DKxQK+XxeVdXFxUV98uf3+w0ZWGuekvxtyhuTUqk0MDCwntWBNZK/hYWFzs5O/b6dm9I2KkEAAQQQQAABBBBAoEkFNpL8raysGLI/Xer3d9Hv95P8/aNpNw8hgAACCCDQKAIkf40yErQDAQQQqKsAyd/v5pckfxt8CaKqquXX0dvbm8lk1qytWvJ3+/Ztm802MjKyZg3cgAACCCCAAAIIIIBAiwhsMPnTh3+G2I/kr64TcypHAAEEEEDgzwiQ/P0ZZ/4KAgggsMUCJH91Sv5a5M0C3UQAAQQQQAABBBBAAIHGEdh48ifDv/LYj+Rvi6fu/HkEEEAAAQQ2Q4DkbzMUqQMBBBBoeIGKyV+hUMjlcqqqyt0+4/F4KBRit0+ZEa5zzV/jTP5pCQIIIIAAAggggAACCLSIwKYkfxVjP5n8hUKheDwuv/Onqmoulyv8OsrnlQ0/FaaBCCCAAAIItKIAyV8rjjp9RgCBFhQon6HJmZuW/KXTaZI//bpAkr8WeWlCNxFAAAEEEEAAAQQQaDqBP5P8pdPpbDZL8teCLxDoMgIIIIBAswuQ/DX7CNJ+BBBAYF0CtZM/RVHS6fT8/Hw4HGbNH2v+mu7FBw1GAAEEEEAAAQQQQKClBOqd/IXD4fn5+XQ6rSgKyd+6ptzchAACCCCAQCMJkPw10mjQFgQQQKBuAmsmf5lMRiZ/s7Oz+qVvLVtmzV9LvTqhswgggAACCCCAAAIINJFAXZO/2dlZmfxlMhmSv7rN0akYAQQQQACBOgqQ/NURl6oRQACBxhEoT/6KxaL2nT9FUTKZTCKRiEQigUCgZdM+fcdJ/proxQdNRQABBBBAAAEEEECgpQTqmvwFAoFIJJJIJAzJX8VJZePMeWkJAggggAACCGgCJH8aBQUEEEBgOwtUnKTJ5C+Xyy0sLGSz2WQyGY1G5+bm9AFYy5a/cyCAAAIIIIAAAggggAACjSrwWzO1ld855ubmotFoMpnMZrMLCwu5X0ehUKg4qdzOs2j6hgACCCCAQNMK/A/5pegXZobgAAAAAABJRU5ErkJggg==" - } - }, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Zen Mode 😌\n", - "\n", - "This is an exclusivity in RetroLab 😎\n", - "\n", - "Activate the palette and choose `Toggle Zen Mode`. The interface will focus on the notebook and the notebook only!\n", - "\n", - "![image.png](attachment:ac1323eb-c6e0-4b7c-80f3-7bf5f84adf98.png)\n", - "\n", - "Press `Escape` to exit, or re-run the `Toggle Zen Mode` command from the palette." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Third Party Extensions 🧩\n", - "\n", - "RetroLab supports third-party extensions developed for JupyterLab 3.0+, using the new distribution system. These extensions can be installed via `pip`.\n", - "\n", - "For example the extension to enable Jupyter Widgets rendering in both JupyterLab and RetroLab can be installed using the following command (run the cell): " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install ipywidgets" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now reload the page and resume from here. In the next section we will be able to create and use Jupyter Widgets!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Widgets\n", - "\n", - "Now let's instantiate a new widget:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "slideshow": { - "slide_type": "fragment" - } - }, - "outputs": [], - "source": [ - "from ipywidgets import IntSlider\n", - "slider = IntSlider()\n", - "slider" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "slider" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Rich Display\n", - "\n", - "Just like in many Jupyter Frontends, RetroLab supports rich display rendering. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import Latex\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}\"\"\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Matplotlib figures:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "x = np.linspace(0, 10, 100)\n", - "\n", - "plt.plot(x, np.sin(x))\n", - "plt.plot(x, np.cos(x))\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or even HTML:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import HTML\n", - "from IPython.display import display\n", - "\n", - "s = \"\"\"\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
Header 1Header 2
row 1, cell 1row 1, cell 2
row 2, cell 1row 2, cell 2
\"\"\"\n", - "h = HTML(s)\n", - "display(h)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## That's it!\n", - "\n", - "Hope you enjoyed the tour. If you have more question or any other issues, don't hesitate to go to the repository on GitHub!\n", - "\n", - "https://github.com/jupyter/notebook" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/bower.json b/bower.json deleted file mode 100644 index 393db02ad..000000000 --- a/bower.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "jupyter-notebook-deps", - "version": "0.0.1", - "dependencies": { - "backbone": "components/backbone#~1.2", - "bootstrap": "bootstrap#~3.4", - "bootstrap-tour": "0.9.0", - "codemirror": "components/codemirror#5.56.0+components1", - "create-react-class": "https://cdn.jsdelivr.net/npm/create-react-class@15.6.3/create-react-class.min.js", - "es6-promise": "~1.0", - "font-awesome": "components/font-awesome#~4.7.0", - "jed": "~1.1.1", - "jquery": "components/jquery#~3.5.0", - "jquery-typeahead": "~2.10.6", - "jquery-ui": "components/jqueryui#~1.12", - "marked": "~0.7", - "MathJax": "^2.7.4", - "moment": "~2.19.3", - "react": "~16.0.0", - "requirejs": "~2.2", - "requirejs-text": "~2.0.15", - "requirejs-plugins": "~1.0.3", - "text-encoding": "~0.1", - "underscore": "components/underscore#~1.8.3", - "xterm.js": "https://unpkg.com/xterm@~3.1.0/dist/xterm.js", - "xterm.js-css": "https://unpkg.com/xterm@~3.1.0/dist/xterm.css", - "xterm.js-fit": "https://unpkg.com/xterm@~3.1.0/dist/addons/fit/fit.js" - } -} diff --git a/git-hooks/README.md b/git-hooks/README.md deleted file mode 100644 index 959b75289..000000000 --- a/git-hooks/README.md +++ /dev/null @@ -1,9 +0,0 @@ -git hooks for Jupyter - -add these to your `.git/hooks` - -For now, we just have `post-checkout` and `post-merge`, -both of which attempt to rebuild javascript and css sourcemaps, -so make sure that you have a fully synced repo whenever you checkout or pull. - -To use these hooks, run `./install-hooks.sh`. diff --git a/git-hooks/install-hooks.sh b/git-hooks/install-hooks.sh deleted file mode 100755 index 60ea64162..000000000 --- a/git-hooks/install-hooks.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -DOTGIT=`git rev-parse --git-dir` -TOPLEVEL=`git rev-parse --show-toplevel` -TO=${DOTGIT}/hooks -FROM=${TOPLEVEL}/git-hooks - -ln -s ${FROM}/post-checkout ${TO}/post-checkout -ln -s ${FROM}/post-merge ${TO}/post-merge diff --git a/git-hooks/post-checkout b/git-hooks/post-checkout deleted file mode 100755 index f329619f5..000000000 --- a/git-hooks/post-checkout +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [[ "$(basename $0)" == "post-merge" ]]; then - PREVIOUS_HEAD=ORIG_HEAD -else - PREVIOUS_HEAD=$1 -fi - -# if style changed (and less available), rebuild sourcemaps -if [[ - ! -z "$(git diff $PREVIOUS_HEAD notebook/static/*/js/**.js)" -]]; then - echo "rebuilding javascript" - python setup.py js || echo "fail to rebuild javascript" -fi - -if [[ - ! -z "$(git diff $PREVIOUS_HEAD notebook/static/*/less/**.less)" -]]; then - echo "rebuilding css sourcemaps" - python setup.py css || echo "fail to recompile css" -fi diff --git a/git-hooks/post-merge b/git-hooks/post-merge deleted file mode 120000 index 5513d1dee..000000000 --- a/git-hooks/post-merge +++ /dev/null @@ -1 +0,0 @@ -post-checkout \ No newline at end of file diff --git a/jupyter-notebook.desktop b/jupyter-notebook.desktop deleted file mode 100644 index 095d5ac65..000000000 --- a/jupyter-notebook.desktop +++ /dev/null @@ -1,11 +0,0 @@ -[Desktop Entry] -Name=Jupyter Notebook -Comment=Run Jupyter Notebook -Exec=jupyter-notebook %f -Terminal=true -Type=Application -Icon=notebook -StartupNotify=true -MimeType=application/x-ipynb+json; -Categories=Development;Education; -Keywords=python; diff --git a/notebook/_sysinfo.py b/notebook/_sysinfo.py deleted file mode 100644 index 951ffd101..000000000 --- a/notebook/_sysinfo.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -Utilities for getting information about Jupyter and the system it's running in. -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import platform -import pprint -import sys -import subprocess - -from ipython_genutils import py3compat, encoding - -import notebook - -def pkg_commit_hash(pkg_path): - """Get short form of commit hash given directory `pkg_path` - - We get the commit hash from git if it's a repo. - - If this fail, we return a not-found placeholder tuple - - Parameters - ---------- - pkg_path : str - directory containing package - only used for getting commit from active repo - - Returns - ------- - hash_from : str - Where we got the hash from - description - hash_str : str - short form of hash - """ - - # maybe we are in a repository, check for a .git folder - p = os.path - cur_path = None - par_path = pkg_path - while cur_path != par_path: - cur_path = par_path - if p.exists(p.join(cur_path, '.git')): - try: - proc = subprocess.Popen(['git', 'rev-parse', '--short', 'HEAD'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=pkg_path) - repo_commit, _ = proc.communicate() - except OSError: - repo_commit = None - - if repo_commit: - return 'repository', repo_commit.strip().decode('ascii') - else: - return u'', u'' - par_path = p.dirname(par_path) - - return u'', u'' - - -def pkg_info(pkg_path): - """Return dict describing the context of this package - - Parameters - ---------- - pkg_path : str - path containing __init__.py for package - - Returns - ------- - context : dict - with named parameters of interest - """ - src, hsh = pkg_commit_hash(pkg_path) - return dict( - notebook_version=notebook.__version__, - notebook_path=pkg_path, - commit_source=src, - commit_hash=hsh, - sys_version=sys.version, - sys_executable=sys.executable, - sys_platform=sys.platform, - platform=platform.platform(), - os_name=os.name, - default_encoding=encoding.DEFAULT_ENCODING, - ) - -def get_sys_info(): - """Return useful information about the system as a dict.""" - p = os.path - path = p.realpath(p.dirname(p.abspath(p.join(notebook.__file__)))) - return pkg_info(path) - diff --git a/notebook/_tz.py b/notebook/_tz.py deleted file mode 100644 index e216a5cdb..000000000 --- a/notebook/_tz.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -Timezone utilities - -Just UTC-awareness right now -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from datetime import tzinfo, timedelta, datetime - -# constant for zero offset -ZERO = timedelta(0) - -class tzUTC(tzinfo): - """tzinfo object for UTC (zero offset)""" - - def utcoffset(self, d): - return ZERO - - def dst(self, d): - return ZERO - -UTC = tzUTC() - -def utc_aware(unaware): - """decorator for adding UTC tzinfo to datetime's utcfoo methods""" - def utc_method(*args, **kwargs): - dt = unaware(*args, **kwargs) - return dt.replace(tzinfo=UTC) - return utc_method - -utcfromtimestamp = utc_aware(datetime.utcfromtimestamp) -utcnow = utc_aware(datetime.utcnow) - -def isoformat(dt): - """Return iso-formatted timestamp - - Like .isoformat(), but uses Z for UTC instead of +00:00 - """ - return dt.isoformat().replace('+00:00', 'Z') diff --git a/notebook/auth/__init__.py b/notebook/auth/__init__.py deleted file mode 100644 index 9f84fa2e9..000000000 --- a/notebook/auth/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .security import passwd diff --git a/notebook/auth/__main__.py b/notebook/auth/__main__.py deleted file mode 100644 index ff413b534..000000000 --- a/notebook/auth/__main__.py +++ /dev/null @@ -1,42 +0,0 @@ -from notebook.auth import passwd -from getpass import getpass -from notebook.config_manager import BaseJSONConfigManager -from jupyter_core.paths import jupyter_config_dir -import argparse -import sys - -def set_password(args): - password = args.password - while not password : - password1 = getpass("" if args.quiet else "Provide password: ") - password_repeat = getpass("" if args.quiet else "Repeat password: ") - if password1 != password_repeat: - print("Passwords do not match, try again") - elif len(password1) < 4: - print("Please provide at least 4 characters") - else: - password = password1 - - password_hash = passwd(password) - cfg = BaseJSONConfigManager(config_dir=jupyter_config_dir()) - cfg.update('jupyter_notebook_config', { - 'NotebookApp': { - 'password': password_hash, - } - }) - if not args.quiet: - print("password stored in config dir: %s" % jupyter_config_dir()) - -def main(argv): - parser = argparse.ArgumentParser(argv[0]) - subparsers = parser.add_subparsers() - parser_password = subparsers.add_parser('password', help='sets a password for your notebook server') - parser_password.add_argument("password", help="password to set, if not given, a password will be queried for (NOTE: this may not be safe)", - nargs="?") - parser_password.add_argument("--quiet", help="suppress messages", action="store_true") - parser_password.set_defaults(function=set_password) - args = parser.parse_args(argv[1:]) - args.function(args) - -if __name__ == "__main__": - main(sys.argv) \ No newline at end of file diff --git a/notebook/auth/login.py b/notebook/auth/login.py deleted file mode 100644 index 16c4e7a35..000000000 --- a/notebook/auth/login.py +++ /dev/null @@ -1,253 +0,0 @@ -"""Tornado handlers for logging into the notebook.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import re -import os - -from urllib.parse import urlparse - -import uuid - -from tornado.escape import url_escape - -from .security import passwd_check, set_password - -from ..base.handlers import IPythonHandler - - -class LoginHandler(IPythonHandler): - """The basic tornado login handler - - authenticates with a hashed password from the configuration. - """ - def _render(self, message=None): - self.write(self.render_template('login.html', - next=url_escape(self.get_argument('next', default=self.base_url)), - message=message, - )) - - def _redirect_safe(self, url, default=None): - """Redirect if url is on our PATH - - Full-domain redirects are allowed if they pass our CORS origin checks. - - Otherwise use default (self.base_url if unspecified). - """ - if default is None: - default = self.base_url - # protect chrome users from mishandling unescaped backslashes. - # \ is not valid in urls, but some browsers treat it as / - # instead of %5C, causing `\\` to behave as `//` - url = url.replace("\\", "%5C") - parsed = urlparse(url) - if parsed.netloc or not (parsed.path + '/').startswith(self.base_url): - # require that next_url be absolute path within our path - allow = False - # OR pass our cross-origin check - if parsed.netloc: - # if full URL, run our cross-origin check: - origin = '%s://%s' % (parsed.scheme, parsed.netloc) - origin = origin.lower() - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(self.allow_origin_pat.match(origin)) - if not allow: - # not allowed, use default - self.log.warning("Not allowing login redirect to %r" % url) - url = default - self.redirect(url) - - def get(self): - if self.current_user: - next_url = self.get_argument('next', default=self.base_url) - self._redirect_safe(next_url) - else: - self._render() - - @property - def hashed_password(self): - return self.password_from_settings(self.settings) - - def passwd_check(self, a, b): - return passwd_check(a, b) - - def post(self): - typed_password = self.get_argument('password', default=u'') - new_password = self.get_argument('new_password', default=u'') - - - - if self.get_login_available(self.settings): - if self.passwd_check(self.hashed_password, typed_password) and not new_password: - self.set_login_cookie(self, uuid.uuid4().hex) - elif self.token and self.token == typed_password: - self.set_login_cookie(self, uuid.uuid4().hex) - if new_password and self.settings.get('allow_password_change'): - config_dir = self.settings.get('config_dir') - config_file = os.path.join(config_dir, 'jupyter_notebook_config.json') - set_password(new_password, config_file=config_file) - self.log.info("Wrote hashed password to %s" % config_file) - else: - self.set_status(401) - self._render(message={'error': 'Invalid credentials'}) - return - - - next_url = self.get_argument('next', default=self.base_url) - self._redirect_safe(next_url) - - @classmethod - def set_login_cookie(cls, handler, user_id=None): - """Call this on handlers to set the login cookie for success""" - cookie_options = handler.settings.get('cookie_options', {}) - cookie_options.setdefault('httponly', True) - # tornado <4.2 has a bug that considers secure==True as soon as - # 'secure' kwarg is passed to set_secure_cookie - if handler.settings.get('secure_cookie', handler.request.protocol == 'https'): - cookie_options.setdefault('secure', True) - cookie_options.setdefault('path', handler.base_url) - handler.set_secure_cookie(handler.cookie_name, user_id, **cookie_options) - return user_id - - auth_header_pat = re.compile(r'token\s+(.+)', re.IGNORECASE) - - @classmethod - def get_token(cls, handler): - """Get the user token from a request - - Default: - - - in URL parameters: ?token= - - in header: Authorization: token - """ - - user_token = handler.get_argument('token', '') - if not user_token: - # get it from Authorization header - m = cls.auth_header_pat.match(handler.request.headers.get('Authorization', '')) - if m: - user_token = m.group(1) - return user_token - - @classmethod - def should_check_origin(cls, handler): - """Should the Handler check for CORS origin validation? - - Origin check should be skipped for token-authenticated requests. - - Returns: - - True, if Handler must check for valid CORS origin. - - False, if Handler should skip origin check since requests are token-authenticated. - """ - return not cls.is_token_authenticated(handler) - - @classmethod - def is_token_authenticated(cls, handler): - """Returns True if handler has been token authenticated. Otherwise, False. - - Login with a token is used to signal certain things, such as: - - - permit access to REST API - - xsrf protection - - skip origin-checks for scripts - """ - if getattr(handler, '_user_id', None) is None: - # ensure get_user has been called, so we know if we're token-authenticated - handler.get_current_user() - return getattr(handler, '_token_authenticated', False) - - @classmethod - def get_user(cls, handler): - """Called by handlers.get_current_user for identifying the current user. - - See tornado.web.RequestHandler.get_current_user for details. - """ - # Can't call this get_current_user because it will collide when - # called on LoginHandler itself. - if getattr(handler, '_user_id', None): - return handler._user_id - user_id = cls.get_user_token(handler) - if user_id is None: - get_secure_cookie_kwargs = handler.settings.get('get_secure_cookie_kwargs', {}) - user_id = handler.get_secure_cookie(handler.cookie_name, **get_secure_cookie_kwargs ) - else: - cls.set_login_cookie(handler, user_id) - # Record that the current request has been authenticated with a token. - # Used in is_token_authenticated above. - handler._token_authenticated = True - if user_id is None: - # If an invalid cookie was sent, clear it to prevent unnecessary - # extra warnings. But don't do this on a request with *no* cookie, - # because that can erroneously log you out (see gh-3365) - if handler.get_cookie(handler.cookie_name) is not None: - handler.log.warning("Clearing invalid/expired login cookie %s", handler.cookie_name) - handler.clear_login_cookie() - if not handler.login_available: - # Completely insecure! No authentication at all. - # No need to warn here, though; validate_security will have already done that. - user_id = 'anonymous' - - # cache value for future retrievals on the same request - handler._user_id = user_id - return user_id - - @classmethod - def get_user_token(cls, handler): - """Identify the user based on a token in the URL or Authorization header - - Returns: - - uuid if authenticated - - None if not - """ - token = handler.token - if not token: - return - # check login token from URL argument or Authorization header - user_token = cls.get_token(handler) - authenticated = False - if user_token == token: - # token-authenticated, set the login cookie - handler.log.debug("Accepting token-authenticated connection from %s", handler.request.remote_ip) - authenticated = True - - if authenticated: - return uuid.uuid4().hex - else: - return None - - - @classmethod - def validate_security(cls, app, ssl_options=None): - """Check the notebook application's security. - - Show messages, or abort if necessary, based on the security configuration. - """ - if not app.ip: - warning = "WARNING: The notebook server is listening on all IP addresses" - if ssl_options is None: - app.log.warning(warning + " and not using encryption. This " - "is not recommended.") - if not app.password and not app.token: - app.log.warning(warning + " and not using authentication. " - "This is highly insecure and not recommended.") - else: - if not app.password and not app.token: - app.log.warning( - "All authentication is disabled." - " Anyone who can connect to this server will be able to run code.") - - @classmethod - def password_from_settings(cls, settings): - """Return the hashed password from the tornado settings. - - If there is no configured password, an empty string will be returned. - """ - return settings.get('password', u'') - - @classmethod - def get_login_available(cls, settings): - """Whether this LoginHandler is needed - and therefore whether the login page should be displayed.""" - return bool(cls.password_from_settings(settings) or settings.get('token')) diff --git a/notebook/auth/logout.py b/notebook/auth/logout.py deleted file mode 100644 index 9eaee1f47..000000000 --- a/notebook/auth/logout.py +++ /dev/null @@ -1,23 +0,0 @@ -"""Tornado handlers for logging out of the notebook. -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from ..base.handlers import IPythonHandler - - -class LogoutHandler(IPythonHandler): - - def get(self): - self.clear_login_cookie() - if self.login_available: - message = {'info': 'Successfully logged out.'} - else: - message = {'warning': 'Cannot log out. Notebook authentication ' - 'is disabled.'} - self.write(self.render_template('logout.html', - message=message)) - - -default_handlers = [(r"/logout", LogoutHandler)] \ No newline at end of file diff --git a/notebook/auth/security.py b/notebook/auth/security.py deleted file mode 100644 index cc9723901..000000000 --- a/notebook/auth/security.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -Password generation for the Notebook. -""" - -from contextlib import contextmanager -import getpass -import hashlib -import io -import json -import os -import random -import traceback -import warnings - -from ipython_genutils.py3compat import cast_bytes, str_to_bytes, cast_unicode -from traitlets.config import Config, ConfigFileNotFound, JSONFileConfigLoader -from jupyter_core.paths import jupyter_config_dir - -# Length of the salt in nr of hex chars, which implies salt_len * 4 -# bits of randomness. -salt_len = 12 - - -def passwd(passphrase=None, algorithm='argon2'): - """Generate hashed password and salt for use in notebook configuration. - - In the notebook configuration, set `c.NotebookApp.password` to - the generated string. - - Parameters - ---------- - passphrase : str - Password to hash. If unspecified, the user is asked to input - and verify a password. - algorithm : str - Hashing algorithm to use (e.g, 'sha1' or any argument supported - by :func:`hashlib.new`, or 'argon2'). - - Returns - ------- - hashed_passphrase : str - Hashed password, in the format 'hash_algorithm:salt:passphrase_hash'. - - Examples - -------- - >>> passwd('mypassword', algorithm='sha1') - 'sha1:7cf3:b7d6da294ea9592a9480c8f52e63cd42cfb9dd12' - - """ - if passphrase is None: - for i in range(3): - p0 = getpass.getpass('Enter password: ') - p1 = getpass.getpass('Verify password: ') - if p0 == p1: - passphrase = p0 - break - else: - print('Passwords do not match.') - else: - raise ValueError('No matching passwords found. Giving up.') - - if algorithm == 'argon2': - from argon2 import PasswordHasher - ph = PasswordHasher( - memory_cost=10240, - time_cost=10, - parallelism=8, - ) - h = ph.hash(passphrase) - - return ':'.join((algorithm, cast_unicode(h, 'ascii'))) - else: - h = hashlib.new(algorithm) - salt = ('%0' + str(salt_len) + 'x') % random.getrandbits(4 * salt_len) - h.update(cast_bytes(passphrase, 'utf-8') + str_to_bytes(salt, 'ascii')) - - return ':'.join((algorithm, salt, h.hexdigest())) - - -def passwd_check(hashed_passphrase, passphrase): - """Verify that a given passphrase matches its hashed version. - - Parameters - ---------- - hashed_passphrase : str - Hashed password, in the format returned by `passwd`. - passphrase : str - Passphrase to validate. - - Returns - ------- - valid : bool - True if the passphrase matches the hash. - - Examples - -------- - >>> from notebook.auth.security import passwd_check - >>> passwd_check('argon2:...', 'mypassword') - True - - >>> passwd_check('argon2:...', 'otherpassword') - False - - >>> passwd_check('sha1:0e112c3ddfce:a68df677475c2b47b6e86d0467eec97ac5f4b85a', - ... 'mypassword') - True - """ - if hashed_passphrase.startswith('argon2:'): - import argon2 - import argon2.exceptions - ph = argon2.PasswordHasher() - try: - return ph.verify(hashed_passphrase[7:], passphrase) - except argon2.exceptions.VerificationError: - return False - else: - try: - algorithm, salt, pw_digest = hashed_passphrase.split(':', 2) - except (ValueError, TypeError): - return False - - try: - h = hashlib.new(algorithm) - except ValueError: - return False - - if len(pw_digest) == 0: - return False - - h.update(cast_bytes(passphrase, 'utf-8') + cast_bytes(salt, 'ascii')) - - return h.hexdigest() == pw_digest - -@contextmanager -def persist_config(config_file=None, mode=0o600): - """Context manager that can be used to modify a config object - - On exit of the context manager, the config will be written back to disk, - by default with user-only (600) permissions. - """ - - if config_file is None: - config_file = os.path.join(jupyter_config_dir(), 'jupyter_notebook_config.json') - - os.makedirs(os.path.dirname(config_file), exist_ok=True) - - loader = JSONFileConfigLoader(os.path.basename(config_file), os.path.dirname(config_file)) - try: - config = loader.load_config() - except ConfigFileNotFound: - config = Config() - - yield config - - with io.open(config_file, 'w', encoding='utf8') as f: - f.write(cast_unicode(json.dumps(config, indent=2))) - - try: - os.chmod(config_file, mode) - except Exception as e: - tb = traceback.format_exc() - warnings.warn("Failed to set permissions on %s:\n%s" % (config_file, tb), - RuntimeWarning) - - -def set_password(password=None, config_file=None): - """Ask user for password, store it in notebook json configuration file""" - - hashed_password = passwd(password) - - with persist_config(config_file) as config: - config.NotebookApp.password = hashed_password diff --git a/notebook/auth/tests/__init__.py b/notebook/auth/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/auth/tests/test_login.py b/notebook/auth/tests/test_login.py deleted file mode 100644 index 2b5574204..000000000 --- a/notebook/auth/tests/test_login.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Tests for login redirects""" - -import requests -from tornado.httputil import url_concat - -from notebook.tests.launchnotebook import NotebookTestBase - - -class LoginTest(NotebookTestBase): - def login(self, next): - first = requests.get(self.base_url() + "login") - first.raise_for_status() - resp = requests.post( - url_concat( - self.base_url() + "login", - {'next': next}, - ), - allow_redirects=False, - data={ - "password": self.token, - "_xsrf": first.cookies.get("_xsrf", ""), - }, - cookies=first.cookies, - ) - resp.raise_for_status() - return resp.headers['Location'] - - def test_next_bad(self): - for bad_next in ( - "//some-host", - "//host" + self.url_prefix + "tree", - "https://google.com", - "/absolute/not/base_url", - ): - url = self.login(next=bad_next) - self.assertEqual(url, self.url_prefix) - assert url - - def test_next_ok(self): - for next_path in ( - "tree/", - "//" + self.url_prefix + "tree", - "notebooks/notebook.ipynb", - "tree//something", - ): - expected = self.url_prefix + next_path - actual = self.login(next=expected) - self.assertEqual(actual, expected) diff --git a/notebook/auth/tests/test_security.py b/notebook/auth/tests/test_security.py deleted file mode 100644 index cf748cda8..000000000 --- a/notebook/auth/tests/test_security.py +++ /dev/null @@ -1,25 +0,0 @@ -from ..security import passwd, passwd_check - -def test_passwd_structure(): - p = passwd('passphrase') - algorithm, hashed = p.split(':') - assert algorithm == 'argon2' - assert hashed.startswith('$argon2id$') - -def test_roundtrip(): - p = passwd('passphrase') - assert passwd_check(p, 'passphrase') == True - -def test_bad(): - p = passwd('passphrase') - assert passwd_check(p, p) == False - assert passwd_check(p, 'a:b:c:d') == False - assert passwd_check(p, 'a:b') == False - -def test_passwd_check_unicode(): - # GH issue #4524 - phash = u'sha1:23862bc21dd3:7a415a95ae4580582e314072143d9c382c491e4f' - assert passwd_check(phash, u"łe¶ŧ←↓→") - phash = (u'argon2:$argon2id$v=19$m=10240,t=10,p=8$' - u'qjjDiZUofUVVnrVYxacnbA$l5pQq1bJ8zglGT2uXP6iOg') - assert passwd_check(phash, u"łe¶ŧ←↓→") diff --git a/notebook/base/__init__.py b/notebook/base/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/base/handlers.py b/notebook/base/handlers.py deleted file mode 100755 index 216480291..000000000 --- a/notebook/base/handlers.py +++ /dev/null @@ -1,952 +0,0 @@ -"""Base Tornado handlers for the notebook server.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import datetime -import functools -import ipaddress -import json -import mimetypes -import os -import re -import sys -import traceback -import types -import warnings -from http.client import responses -from http.cookies import Morsel - -from urllib.parse import urlparse -from jinja2 import TemplateNotFound -from tornado import web, gen, escape, httputil -from tornado.log import app_log -import prometheus_client - -from notebook._sysinfo import get_sys_info - -from traitlets.config import Application -from ipython_genutils.path import filefind -from ipython_genutils.py3compat import string_types - -import notebook -from notebook._tz import utcnow -from notebook.i18n import combine_translations -from notebook.utils import is_hidden, url_path_join, url_is_absolute, url_escape, urldecode_unix_socket_path -from notebook.services.security import csp_report_uri - -#----------------------------------------------------------------------------- -# Top-level handlers -#----------------------------------------------------------------------------- -non_alphanum = re.compile(r'[^A-Za-z0-9]') - -_sys_info_cache = None -def json_sys_info(): - global _sys_info_cache - if _sys_info_cache is None: - _sys_info_cache = json.dumps(get_sys_info()) - return _sys_info_cache - -def log(): - if Application.initialized(): - return Application.instance().log - else: - return app_log - -class AuthenticatedHandler(web.RequestHandler): - """A RequestHandler with an authenticated user.""" - - @property - def content_security_policy(self): - """The default Content-Security-Policy header - - Can be overridden by defining Content-Security-Policy in settings['headers'] - """ - if 'Content-Security-Policy' in self.settings.get('headers', {}): - # user-specified, don't override - return self.settings['headers']['Content-Security-Policy'] - - return '; '.join([ - "frame-ancestors 'self'", - # Make sure the report-uri is relative to the base_url - "report-uri " + self.settings.get('csp_report_uri', url_path_join(self.base_url, csp_report_uri)), - ]) - - def set_default_headers(self): - headers = {} - headers["X-Content-Type-Options"] = "nosniff" - headers.update(self.settings.get('headers', {})) - - headers["Content-Security-Policy"] = self.content_security_policy - - # Allow for overriding headers - for header_name, value in headers.items(): - try: - self.set_header(header_name, value) - except Exception as e: - # tornado raise Exception (not a subclass) - # if method is unsupported (websocket and Access-Control-Allow-Origin - # for example, so just ignore) - self.log.debug(e) - - def force_clear_cookie(self, name, path="/", domain=None): - """Deletes the cookie with the given name. - - Tornado's cookie handling currently (Jan 2018) stores cookies in a dict - keyed by name, so it can only modify one cookie with a given name per - response. The browser can store multiple cookies with the same name - but different domains and/or paths. This method lets us clear multiple - cookies with the same name. - - Due to limitations of the cookie protocol, you must pass the same - path and domain to clear a cookie as were used when that cookie - was set (but there is no way to find out on the server side - which values were used for a given cookie). - """ - name = escape.native_str(name) - expires = datetime.datetime.utcnow() - datetime.timedelta(days=365) - - morsel = Morsel() - morsel.set(name, '', '""') - morsel['expires'] = httputil.format_timestamp(expires) - morsel['path'] = path - if domain: - morsel['domain'] = domain - self.add_header("Set-Cookie", morsel.OutputString()) - - def clear_login_cookie(self): - cookie_options = self.settings.get('cookie_options', {}) - path = cookie_options.setdefault('path', self.base_url) - self.clear_cookie(self.cookie_name, path=path) - if path and path != '/': - # also clear cookie on / to ensure old cookies are cleared - # after the change in path behavior (changed in notebook 5.2.2). - # N.B. This bypasses the normal cookie handling, which can't update - # two cookies with the same name. See the method above. - self.force_clear_cookie(self.cookie_name) - - def get_current_user(self): - if self.login_handler is None: - return 'anonymous' - return self.login_handler.get_user(self) - - def skip_check_origin(self): - """Ask my login_handler if I should skip the origin_check - - For example: in the default LoginHandler, if a request is token-authenticated, - origin checking should be skipped. - """ - if self.request.method == 'OPTIONS': - # no origin-check on options requests, which are used to check origins! - return True - if self.login_handler is None or not hasattr(self.login_handler, 'should_check_origin'): - return False - return not self.login_handler.should_check_origin(self) - - @property - def token_authenticated(self): - """Have I been authenticated with a token?""" - if self.login_handler is None or not hasattr(self.login_handler, 'is_token_authenticated'): - return False - return self.login_handler.is_token_authenticated(self) - - @property - def cookie_name(self): - default_cookie_name = non_alphanum.sub('-', 'username-{}'.format( - self.request.host - )) - return self.settings.get('cookie_name', default_cookie_name) - - @property - def logged_in(self): - """Is a user currently logged in?""" - user = self.get_current_user() - return (user and not user == 'anonymous') - - @property - def login_handler(self): - """Return the login handler for this application, if any.""" - return self.settings.get('login_handler_class', None) - - @property - def token(self): - """Return the login token for this application, if any.""" - return self.settings.get('token', None) - - @property - def login_available(self): - """May a user proceed to log in? - - This returns True if login capability is available, irrespective of - whether the user is already logged in or not. - - """ - if self.login_handler is None: - return False - return bool(self.login_handler.get_login_available(self.settings)) - - -class IPythonHandler(AuthenticatedHandler): - """IPython-specific extensions to authenticated handling - - Mostly property shortcuts to IPython-specific settings. - """ - - @property - def ignore_minified_js(self): - """Wether to user bundle in template. (*.min files) - - Mainly use for development and avoid file recompilation - """ - return self.settings.get('ignore_minified_js', False) - - @property - def config(self): - return self.settings.get('config', None) - - @property - def log(self): - """use the IPython log by default, falling back on tornado's logger""" - return log() - - @property - def jinja_template_vars(self): - """User-supplied values to supply to jinja templates.""" - return self.settings.get('jinja_template_vars', {}) - - #--------------------------------------------------------------- - # URLs - #--------------------------------------------------------------- - - @property - def version_hash(self): - """The version hash to use for cache hints for static files""" - return self.settings.get('version_hash', '') - - @property - def mathjax_url(self): - url = self.settings.get('mathjax_url', '') - if not url or url_is_absolute(url): - return url - return url_path_join(self.base_url, url) - - @property - def mathjax_config(self): - return self.settings.get('mathjax_config', 'TeX-AMS-MML_HTMLorMML-full,Safe') - - @property - def base_url(self): - return self.settings.get('base_url', '/') - - @property - def default_url(self): - return self.settings.get('default_url', '') - - @property - def ws_url(self): - return self.settings.get('websocket_url', '') - - @property - def contents_js_source(self): - self.log.debug("Using contents: %s", self.settings.get('contents_js_source', - 'services/contents')) - return self.settings.get('contents_js_source', 'services/contents') - - #--------------------------------------------------------------- - # Manager objects - #--------------------------------------------------------------- - - @property - def kernel_manager(self): - return self.settings['kernel_manager'] - - @property - def contents_manager(self): - return self.settings['contents_manager'] - - @property - def session_manager(self): - return self.settings['session_manager'] - - @property - def terminal_manager(self): - return self.settings['terminal_manager'] - - @property - def kernel_spec_manager(self): - return self.settings['kernel_spec_manager'] - - @property - def config_manager(self): - return self.settings['config_manager'] - - #--------------------------------------------------------------- - # CORS - #--------------------------------------------------------------- - - @property - def allow_origin(self): - """Normal Access-Control-Allow-Origin""" - return self.settings.get('allow_origin', '') - - @property - def allow_origin_pat(self): - """Regular expression version of allow_origin""" - return self.settings.get('allow_origin_pat', None) - - @property - def allow_credentials(self): - """Whether to set Access-Control-Allow-Credentials""" - return self.settings.get('allow_credentials', False) - - def set_default_headers(self): - """Add CORS headers, if defined""" - super().set_default_headers() - if self.allow_origin: - self.set_header("Access-Control-Allow-Origin", self.allow_origin) - elif self.allow_origin_pat: - origin = self.get_origin() - if origin and self.allow_origin_pat.match(origin): - self.set_header("Access-Control-Allow-Origin", origin) - elif ( - self.token_authenticated - and "Access-Control-Allow-Origin" not in - self.settings.get('headers', {}) - ): - # allow token-authenticated requests cross-origin by default. - # only apply this exception if allow-origin has not been specified. - self.set_header('Access-Control-Allow-Origin', - self.request.headers.get('Origin', '')) - - if self.allow_credentials: - self.set_header("Access-Control-Allow-Credentials", 'true') - - def set_attachment_header(self, filename): - """Set Content-Disposition: attachment header - - As a method to ensure handling of filename encoding - """ - escaped_filename = url_escape(filename) - self.set_header('Content-Disposition', - 'attachment;' - " filename*=utf-8''{utf8}" - .format( - utf8=escaped_filename, - ) - ) - - def get_origin(self): - # Handle WebSocket Origin naming convention differences - # The difference between version 8 and 13 is that in 8 the - # client sends a "Sec-Websocket-Origin" header and in 13 it's - # simply "Origin". - if "Origin" in self.request.headers: - origin = self.request.headers.get("Origin") - else: - origin = self.request.headers.get("Sec-Websocket-Origin", None) - return origin - - # origin_to_satisfy_tornado is present because tornado requires - # check_origin to take an origin argument, but we don't use it - def check_origin(self, origin_to_satisfy_tornado=""): - """Check Origin for cross-site API requests, including websockets - - Copied from WebSocket with changes: - - - allow unspecified host/origin (e.g. scripts) - - allow token-authenticated requests - """ - if self.allow_origin == '*' or self.skip_check_origin(): - return True - - host = self.request.headers.get("Host") - origin = self.request.headers.get("Origin") - - # If no header is provided, let the request through. - # Origin can be None for: - # - same-origin (IE, Firefox) - # - Cross-site POST form (IE, Firefox) - # - Scripts - # The cross-site POST (XSRF) case is handled by tornado's xsrf_token - if origin is None or host is None: - return True - - origin = origin.lower() - origin_host = urlparse(origin).netloc - - # OK if origin matches host - if origin_host == host: - return True - - # Check CORS headers - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(self.allow_origin_pat.match(origin)) - else: - # No CORS headers deny the request - allow = False - if not allow: - self.log.warning("Blocking Cross Origin API request for %s. Origin: %s, Host: %s", - self.request.path, origin, host, - ) - return allow - - def check_referer(self): - """Check Referer for cross-site requests. - - Disables requests to certain endpoints with - external or missing Referer. - - If set, allow_origin settings are applied to the Referer - to whitelist specific cross-origin sites. - - Used on GET for api endpoints and /files/ - to block cross-site inclusion (XSSI). - """ - - if self.allow_origin == "*" or self.skip_check_origin(): - return True - - host = self.request.headers.get("Host") - referer = self.request.headers.get("Referer") - - if not host: - self.log.warning("Blocking request with no host") - return False - if not referer: - self.log.warning("Blocking request with no referer") - return False - - referer_url = urlparse(referer) - referer_host = referer_url.netloc - if referer_host == host: - return True - - # apply cross-origin checks to Referer: - origin = "{}://{}".format(referer_url.scheme, referer_url.netloc) - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(self.allow_origin_pat.match(origin)) - else: - # No CORS settings, deny the request - allow = False - - if not allow: - self.log.warning("Blocking Cross Origin request for %s. Referer: %s, Host: %s", - self.request.path, origin, host, - ) - return allow - - def check_xsrf_cookie(self): - """Bypass xsrf cookie checks when token-authenticated""" - if self.token_authenticated or self.settings.get('disable_check_xsrf', False): - # Token-authenticated requests do not need additional XSRF-check - # Servers without authentication are vulnerable to XSRF - return - try: - return super().check_xsrf_cookie() - except web.HTTPError as e: - if self.request.method in {'GET', 'HEAD'}: - # Consider Referer a sufficient cross-origin check for GET requests - if not self.check_referer(): - referer = self.request.headers.get('Referer') - if referer: - msg = "Blocking Cross Origin request from {}.".format(referer) - else: - msg = "Blocking request from unknown origin" - raise web.HTTPError(403, msg) from e - else: - raise - - def check_host(self): - """Check the host header if remote access disallowed. - - Returns True if the request should continue, False otherwise. - """ - if self.settings.get('allow_remote_access', False): - return True - - # Remove port (e.g. ':8888') from host - host = re.match(r'^(.*?)(:\d+)?$', self.request.host).group(1) - - # Browsers format IPv6 addresses like [::1]; we need to remove the [] - if host.startswith('[') and host.endswith(']'): - host = host[1:-1] - - # UNIX socket handling - check_host = urldecode_unix_socket_path(host) - if check_host.startswith('/') and os.path.exists(check_host): - allow = True - else: - try: - addr = ipaddress.ip_address(host) - except ValueError: - # Not an IP address: check against hostnames - allow = host in self.settings.get('local_hostnames', ['localhost']) - else: - allow = addr.is_loopback - - if not allow: - self.log.warning( - ("Blocking request with non-local 'Host' %s (%s). " - "If the notebook should be accessible at that name, " - "set NotebookApp.allow_remote_access to disable the check."), - host, self.request.host - ) - return allow - - def prepare(self): - if not self.check_host(): - raise web.HTTPError(403) - return super().prepare() - - #--------------------------------------------------------------- - # template rendering - #--------------------------------------------------------------- - - def get_template(self, name): - """Return the jinja template object for a given name""" - return self.settings['jinja2_env'].get_template(name) - - def render_template(self, name, **ns): - ns.update(self.template_namespace) - template = self.get_template(name) - return template.render(**ns) - - @property - def template_namespace(self): - return dict( - base_url=self.base_url, - default_url=self.default_url, - ws_url=self.ws_url, - logged_in=self.logged_in, - allow_password_change=self.settings.get('allow_password_change'), - login_available=self.login_available, - token_available=bool(self.token), - static_url=self.static_url, - sys_info=json_sys_info(), - contents_js_source=self.contents_js_source, - version_hash=self.version_hash, - ignore_minified_js=self.ignore_minified_js, - xsrf_form_html=self.xsrf_form_html, - token=self.token, - xsrf_token=self.xsrf_token.decode('utf8'), - nbjs_translations=json.dumps(combine_translations( - self.request.headers.get('Accept-Language', ''))), - **self.jinja_template_vars - ) - - def get_json_body(self): - """Return the body of the request as JSON data.""" - if not self.request.body: - return None - # Do we need to call body.decode('utf-8') here? - body = self.request.body.strip().decode(u'utf-8') - try: - model = json.loads(body) - except Exception as e: - self.log.debug("Bad JSON: %r", body) - self.log.error("Couldn't parse JSON", exc_info=True) - raise web.HTTPError(400, u'Invalid JSON in body of request') from e - return model - - def write_error(self, status_code, **kwargs): - """render custom error pages""" - exc_info = kwargs.get('exc_info') - message = '' - status_message = responses.get(status_code, 'Unknown HTTP Error') - exception = '(unknown)' - if exc_info: - exception = exc_info[1] - # get the custom message, if defined - try: - message = exception.log_message % exception.args - except Exception: - pass - - # construct the custom reason, if defined - reason = getattr(exception, 'reason', '') - if reason: - status_message = reason - - # build template namespace - ns = dict( - status_code=status_code, - status_message=status_message, - message=message, - exception=exception, - ) - - self.set_header('Content-Type', 'text/html') - # render the template - try: - html = self.render_template('%s.html' % status_code, **ns) - except TemplateNotFound: - html = self.render_template('error.html', **ns) - - self.write(html) - - -class APIHandler(IPythonHandler): - """Base class for API handlers""" - - def prepare(self): - if not self.check_origin(): - raise web.HTTPError(404) - return super().prepare() - - def write_error(self, status_code, **kwargs): - """APIHandler errors are JSON, not human pages""" - self.set_header('Content-Type', 'application/json') - message = responses.get(status_code, 'Unknown HTTP Error') - reply = { - 'message': message, - } - exc_info = kwargs.get('exc_info') - if exc_info: - e = exc_info[1] - if isinstance(e, HTTPError): - reply['message'] = e.log_message or message - reply['reason'] = e.reason - else: - reply['message'] = 'Unhandled error' - reply['reason'] = None - reply['traceback'] = ''.join(traceback.format_exception(*exc_info)) - self.log.warning(reply['message']) - self.finish(json.dumps(reply)) - - def get_current_user(self): - """Raise 403 on API handlers instead of redirecting to human login page""" - # preserve _user_cache so we don't raise more than once - if hasattr(self, '_user_cache'): - return self._user_cache - self._user_cache = user = super().get_current_user() - return user - - def get_login_url(self): - # if get_login_url is invoked in an API handler, - # that means @web.authenticated is trying to trigger a redirect. - # instead of redirecting, raise 403 instead. - if not self.current_user: - raise web.HTTPError(403) - return super().get_login_url() - - @property - def content_security_policy(self): - csp = '; '.join([ - super().content_security_policy, - "default-src 'none'", - ]) - return csp - - # set _track_activity = False on API handlers that shouldn't track activity - _track_activity = True - - def update_api_activity(self): - """Update last_activity of API requests""" - # record activity of authenticated requests - if ( - self._track_activity - and getattr(self, '_user_cache', None) - and self.get_argument('no_track_activity', None) is None - ): - self.settings['api_last_activity'] = utcnow() - - def finish(self, *args, **kwargs): - self.update_api_activity() - self.set_header('Content-Type', 'application/json') - return super().finish(*args, **kwargs) - - def options(self, *args, **kwargs): - if 'Access-Control-Allow-Headers' in self.settings.get('headers', {}): - self.set_header('Access-Control-Allow-Headers', self.settings['headers']['Access-Control-Allow-Headers']) - else: - self.set_header('Access-Control-Allow-Headers', - 'accept, content-type, authorization, x-xsrftoken') - self.set_header('Access-Control-Allow-Methods', - 'GET, PUT, POST, PATCH, DELETE, OPTIONS') - - # if authorization header is requested, - # that means the request is token-authenticated. - # avoid browser-side rejection of the preflight request. - # only allow this exception if allow_origin has not been specified - # and notebook authentication is enabled. - # If the token is not valid, the 'real' request will still be rejected. - requested_headers = self.request.headers.get('Access-Control-Request-Headers', '').split(',') - if requested_headers and any( - h.strip().lower() == 'authorization' - for h in requested_headers - ) and ( - # FIXME: it would be even better to check specifically for token-auth, - # but there is currently no API for this. - self.login_available - ) and ( - self.allow_origin - or self.allow_origin_pat - or 'Access-Control-Allow-Origin' in self.settings.get('headers', {}) - ): - self.set_header('Access-Control-Allow-Origin', - self.request.headers.get('Origin', '')) - - -class Template404(IPythonHandler): - """Render our 404 template""" - def prepare(self): - raise web.HTTPError(404) - - -class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler): - """static files should only be accessible when logged in""" - - @property - def content_security_policy(self): - # In case we're serving HTML/SVG, confine any Javascript to a unique - # origin so it can't interact with the notebook server. - return super().content_security_policy + "; sandbox allow-scripts" - - @web.authenticated - def head(self, path): - self.check_xsrf_cookie() - return super().head(path) - - @web.authenticated - def get(self, path): - self.check_xsrf_cookie() - - if os.path.splitext(path)[1] == '.ipynb' or self.get_argument("download", False): - name = path.rsplit('/', 1)[-1] - self.set_attachment_header(name) - - return web.StaticFileHandler.get(self, path) - - def get_content_type(self): - path = self.absolute_path.strip('/') - if '/' in path: - _, name = path.rsplit('/', 1) - else: - name = path - if name.endswith('.ipynb'): - return 'application/x-ipynb+json' - else: - cur_mime = mimetypes.guess_type(name)[0] - if cur_mime == 'text/plain': - return 'text/plain; charset=UTF-8' - else: - return super().get_content_type() - - def set_headers(self): - super().set_headers() - # disable browser caching, rely on 304 replies for savings - if "v" not in self.request.arguments: - self.add_header("Cache-Control", "no-cache") - - def compute_etag(self): - return None - - def validate_absolute_path(self, root, absolute_path): - """Validate and return the absolute path. - - Requires tornado 3.1 - - Adding to tornado's own handling, forbids the serving of hidden files. - """ - abs_path = super().validate_absolute_path(root, absolute_path) - abs_root = os.path.abspath(root) - if is_hidden(abs_path, abs_root) and not self.contents_manager.allow_hidden: - self.log.info("Refusing to serve hidden file, via 404 Error, use flag 'ContentsManager.allow_hidden' to enable") - raise web.HTTPError(404) - return abs_path - - -def json_errors(method): - """Decorate methods with this to return GitHub style JSON errors. - - This should be used on any JSON API on any handler method that can raise HTTPErrors. - - This will grab the latest HTTPError exception using sys.exc_info - and then: - - 1. Set the HTTP status code based on the HTTPError - 2. Create and return a JSON body with a message field describing - the error in a human readable form. - """ - warnings.warn('@json_errors is deprecated in notebook 5.2.0. Subclass APIHandler instead.', - DeprecationWarning, - stacklevel=2, - ) - @functools.wraps(method) - def wrapper(self, *args, **kwargs): - self.write_error = types.MethodType(APIHandler.write_error, self) - return method(self, *args, **kwargs) - return wrapper - - - -#----------------------------------------------------------------------------- -# File handler -#----------------------------------------------------------------------------- - -# to minimize subclass changes: -HTTPError = web.HTTPError - -class FileFindHandler(IPythonHandler, web.StaticFileHandler): - """subclass of StaticFileHandler for serving files from a search path""" - - # cache search results, don't search for files more than once - _static_paths = {} - - def set_headers(self): - super().set_headers() - # disable browser caching, rely on 304 replies for savings - if "v" not in self.request.arguments or \ - any(self.request.path.startswith(path) for path in self.no_cache_paths): - self.set_header("Cache-Control", "no-cache") - - def initialize(self, path, default_filename=None, no_cache_paths=None): - self.no_cache_paths = no_cache_paths or [] - - if isinstance(path, string_types): - path = [path] - - self.root = tuple( - os.path.abspath(os.path.expanduser(p)) + os.sep for p in path - ) - self.default_filename = default_filename - - def compute_etag(self): - return None - - @classmethod - def get_absolute_path(cls, roots, path): - """locate a file to serve on our static file search path""" - with cls._lock: - if path in cls._static_paths: - return cls._static_paths[path] - try: - abspath = os.path.abspath(filefind(path, roots)) - except IOError: - # IOError means not found - return '' - - cls._static_paths[path] = abspath - - - log().debug("Path %s served from %s"%(path, abspath)) - return abspath - - def validate_absolute_path(self, root, absolute_path): - """check if the file should be served (raises 404, 403, etc.)""" - if absolute_path == '': - raise web.HTTPError(404) - - for root in self.root: - if (absolute_path + os.sep).startswith(root): - break - - return super().validate_absolute_path(root, absolute_path) - - -class APIVersionHandler(APIHandler): - - def get(self): - # not authenticated, so give as few info as possible - self.finish(json.dumps({"version":notebook.__version__})) - - -class TrailingSlashHandler(web.RequestHandler): - """Simple redirect handler that strips trailing slashes - - This should be the first, highest priority handler. - """ - - def get(self): - path, *rest = self.request.uri.partition("?") - # trim trailing *and* leading / - # to avoid misinterpreting repeated '//' - path = "/" + path.strip("/") - new_uri = "".join([path, *rest]) - self.redirect(new_uri) - - post = put = get - - -class FilesRedirectHandler(IPythonHandler): - """Handler for redirecting relative URLs to the /files/ handler""" - - @staticmethod - def redirect_to_files(self, path): - """make redirect logic a reusable static method - - so it can be called from other handlers. - """ - cm = self.contents_manager - if cm.dir_exists(path): - # it's a *directory*, redirect to /tree - url = url_path_join(self.base_url, 'tree', url_escape(path)) - else: - orig_path = path - # otherwise, redirect to /files - parts = path.split('/') - - if not cm.file_exists(path=path) and 'files' in parts: - # redirect without files/ iff it would 404 - # this preserves pre-2.0-style 'files/' links - self.log.warning("Deprecated files/ URL: %s", orig_path) - parts.remove('files') - path = '/'.join(parts) - - if not cm.file_exists(path=path): - raise web.HTTPError(404) - - url = url_path_join(self.base_url, 'files', url_escape(path)) - self.log.debug("Redirecting %s to %s", self.request.path, url) - self.redirect(url) - - def get(self, path=''): - return self.redirect_to_files(self, path) - - -class RedirectWithParams(web.RequestHandler): - """Sam as web.RedirectHandler, but preserves URL parameters""" - def initialize(self, url, permanent=True): - self._url = url - self._permanent = permanent - - def get(self): - sep = '&' if '?' in self._url else '?' - url = sep.join([self._url, self.request.query]) - self.redirect(url, permanent=self._permanent) - - -class PrometheusMetricsHandler(IPythonHandler): - """ - Return prometheus metrics for this notebook server - """ - def get(self): - if self.settings['authenticate_prometheus'] and not self.logged_in: - raise web.HTTPError(403) - - self.set_header('Content-Type', prometheus_client.CONTENT_TYPE_LATEST) - self.write(prometheus_client.generate_latest(prometheus_client.REGISTRY)) - - -#----------------------------------------------------------------------------- -# URL pattern fragments for re-use -#----------------------------------------------------------------------------- - -# path matches any number of `/foo[/bar...]` or just `/` or '' -path_regex = r"(?P(?:(?:/[^/]+)+|/?))" - -#----------------------------------------------------------------------------- -# URL to handler mappings -#----------------------------------------------------------------------------- - - -default_handlers = [ - (r".*/", TrailingSlashHandler), - (r"api", APIVersionHandler), - (r'/(robots\.txt|favicon\.ico)', web.StaticFileHandler), - (r'/metrics', PrometheusMetricsHandler) -] diff --git a/notebook/base/zmqhandlers.py b/notebook/base/zmqhandlers.py deleted file mode 100644 index c4d4554a8..000000000 --- a/notebook/base/zmqhandlers.py +++ /dev/null @@ -1,302 +0,0 @@ -"""Tornado handlers for WebSocket <-> ZMQ sockets.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import json -import struct -import sys -from urllib.parse import urlparse - -import tornado -from tornado import gen, ioloop, web -from tornado.iostream import StreamClosedError -from tornado.websocket import WebSocketHandler, WebSocketClosedError - -from jupyter_client.session import Session -try: - from jupyter_client.jsonutil import json_default, extract_dates -except ImportError: - from jupyter_client.jsonutil import ( - date_default as json_default, extract_dates - ) -from ipython_genutils.py3compat import cast_unicode - -from notebook.utils import maybe_future -from .handlers import IPythonHandler - - -def serialize_binary_message(msg): - """serialize a message as a binary blob - - Header: - - 4 bytes: number of msg parts (nbufs) as 32b int - 4 * nbufs bytes: offset for each buffer as integer as 32b int - - Offsets are from the start of the buffer, including the header. - - Returns - ------- - - The message serialized to bytes. - - """ - # don't modify msg or buffer list in-place - msg = msg.copy() - buffers = list(msg.pop('buffers')) - bmsg = json.dumps(msg, default=json_default).encode('utf8') - buffers.insert(0, bmsg) - nbufs = len(buffers) - offsets = [4 * (nbufs + 1)] - for buf in buffers[:-1]: - offsets.append(offsets[-1] + len(buf)) - offsets_buf = struct.pack('!' + 'I' * (nbufs + 1), nbufs, *offsets) - buffers.insert(0, offsets_buf) - return b''.join(buffers) - - -def deserialize_binary_message(bmsg): - """deserialize a message from a binary blog - - Header: - - 4 bytes: number of msg parts (nbufs) as 32b int - 4 * nbufs bytes: offset for each buffer as integer as 32b int - - Offsets are from the start of the buffer, including the header. - - Returns - ------- - - message dictionary - """ - nbufs = struct.unpack('!i', bmsg[:4])[0] - offsets = list(struct.unpack('!' + 'I' * nbufs, bmsg[4:4*(nbufs+1)])) - offsets.append(None) - bufs = [] - for start, stop in zip(offsets[:-1], offsets[1:]): - bufs.append(bmsg[start:stop]) - msg = json.loads(bufs[0].decode('utf8')) - msg['header'] = extract_dates(msg['header']) - msg['parent_header'] = extract_dates(msg['parent_header']) - msg['buffers'] = bufs[1:] - return msg - -# ping interval for keeping websockets alive (30 seconds) -WS_PING_INTERVAL = 30000 - - -class WebSocketMixin(object): - """Mixin for common websocket options""" - ping_callback = None - last_ping = 0 - last_pong = 0 - stream = None - - @property - def ping_interval(self): - """The interval for websocket keep-alive pings. - - Set ws_ping_interval = 0 to disable pings. - """ - return self.settings.get('ws_ping_interval', WS_PING_INTERVAL) - - @property - def ping_timeout(self): - """If no ping is received in this many milliseconds, - close the websocket connection (VPNs, etc. can fail to cleanly close ws connections). - Default is max of 3 pings or 30 seconds. - """ - return self.settings.get('ws_ping_timeout', - max(3 * self.ping_interval, WS_PING_INTERVAL) - ) - - def check_origin(self, origin=None): - """Check Origin == Host or Access-Control-Allow-Origin. - - Tornado >= 4 calls this method automatically, raising 403 if it returns False. - """ - - if self.allow_origin == '*' or ( - hasattr(self, 'skip_check_origin') and self.skip_check_origin()): - return True - - host = self.request.headers.get("Host") - if origin is None: - origin = self.get_origin() - - # If no origin or host header is provided, assume from script - if origin is None or host is None: - return True - - origin = origin.lower() - origin_host = urlparse(origin).netloc - - # OK if origin matches host - if origin_host == host: - return True - - # Check CORS headers - if self.allow_origin: - allow = self.allow_origin == origin - elif self.allow_origin_pat: - allow = bool(self.allow_origin_pat.match(origin)) - else: - # No CORS headers deny the request - allow = False - if not allow: - self.log.warning("Blocking Cross Origin WebSocket Attempt. Origin: %s, Host: %s", - origin, host, - ) - return allow - - def clear_cookie(self, *args, **kwargs): - """meaningless for websockets""" - pass - - def open(self, *args, **kwargs): - self.log.debug("Opening websocket %s", self.request.path) - - # start the pinging - if self.ping_interval > 0: - loop = ioloop.IOLoop.current() - self.last_ping = loop.time() # Remember time of last ping - self.last_pong = self.last_ping - self.ping_callback = ioloop.PeriodicCallback( - self.send_ping, self.ping_interval, - ) - self.ping_callback.start() - return super(WebSocketMixin, self).open(*args, **kwargs) - - def send_ping(self): - """send a ping to keep the websocket alive""" - if self.ws_connection is None and self.ping_callback is not None: - self.ping_callback.stop() - return - - # check for timeout on pong. Make sure that we really have sent a recent ping in - # case the machine with both server and client has been suspended since the last ping. - now = ioloop.IOLoop.current().time() - since_last_pong = 1e3 * (now - self.last_pong) - since_last_ping = 1e3 * (now - self.last_ping) - if since_last_ping < 2*self.ping_interval and since_last_pong > self.ping_timeout: - self.log.warning("WebSocket ping timeout after %i ms.", since_last_pong) - self.close() - return - try: - self.ping(b'') - except (StreamClosedError, WebSocketClosedError): - # websocket has been closed, stop pinging - self.ping_callback.stop() - return - - self.last_ping = now - - def on_pong(self, data): - self.last_pong = ioloop.IOLoop.current().time() - - -class ZMQStreamHandler(WebSocketMixin, WebSocketHandler): - - if tornado.version_info < (4,1): - """Backport send_error from tornado 4.1 to 4.0""" - def send_error(self, *args, **kwargs): - if self.stream is None: - super(WebSocketHandler, self).send_error(*args, **kwargs) - else: - # If we get an uncaught exception during the handshake, - # we have no choice but to abruptly close the connection. - # TODO: for uncaught exceptions after the handshake, - # we can close the connection more gracefully. - self.stream.close() - - - def _reserialize_reply(self, msg_or_list, channel=None): - """Reserialize a reply message using JSON. - - msg_or_list can be an already-deserialized msg dict or the zmq buffer list. - If it is the zmq list, it will be deserialized with self.session. - - This takes the msg list from the ZMQ socket and serializes the result for the websocket. - This method should be used by self._on_zmq_reply to build messages that can - be sent back to the browser. - - """ - if isinstance(msg_or_list, dict): - # already unpacked - msg = msg_or_list - else: - idents, msg_list = self.session.feed_identities(msg_or_list) - msg = self.session.deserialize(msg_list) - if channel: - msg['channel'] = channel - if msg['buffers']: - buf = serialize_binary_message(msg) - return buf - else: - smsg = json.dumps(msg, default=json_default) - return cast_unicode(smsg) - - def _on_zmq_reply(self, stream, msg_list): - # Sometimes this gets triggered when the on_close method is scheduled in the - # eventloop but hasn't been called. - if self.ws_connection is None or stream.closed(): - self.log.warning("zmq message arrived on closed channel") - self.close() - return - channel = getattr(stream, 'channel', None) - try: - msg = self._reserialize_reply(msg_list, channel=channel) - except Exception: - self.log.critical("Malformed message: %r" % msg_list, exc_info=True) - return - - try: - self.write_message(msg, binary=isinstance(msg, bytes)) - except (StreamClosedError, WebSocketClosedError): - self.log.warning("zmq message arrived on closed channel") - self.close() - return - - -class AuthenticatedZMQStreamHandler(ZMQStreamHandler, IPythonHandler): - - def set_default_headers(self): - """Undo the set_default_headers in IPythonHandler - - which doesn't make sense for websockets - """ - pass - - def pre_get(self): - """Run before finishing the GET request - - Extend this method to add logic that should fire before - the websocket finishes completing. - """ - # authenticate the request before opening the websocket - if self.get_current_user() is None: - self.log.warning("Couldn't authenticate WebSocket connection") - raise web.HTTPError(403) - - if self.get_argument('session_id', False): - self.session.session = cast_unicode(self.get_argument('session_id')) - else: - self.log.warning("No session ID specified") - - @gen.coroutine - def get(self, *args, **kwargs): - # pre_get can be a coroutine in subclasses - # assign and yield in two step to avoid tornado 3 issues - res = self.pre_get() - yield maybe_future(res) - res = super().get(*args, **kwargs) - yield maybe_future(res) - - def initialize(self): - self.log.debug("Initializing websocket connection %s", self.request.path) - self.session = Session(config=self.config) - - def get_compression_options(self): - return self.settings.get('websocket_compression_options', None) diff --git a/notebook/bundler/__init__.py b/notebook/bundler/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/bundler/__main__.py b/notebook/bundler/__main__.py deleted file mode 100644 index cde186dbb..000000000 --- a/notebook/bundler/__main__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from .bundlerextensions import main - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/notebook/bundler/bundlerextensions.py b/notebook/bundler/bundlerextensions.py deleted file mode 100644 index 2ac346f97..000000000 --- a/notebook/bundler/bundlerextensions.py +++ /dev/null @@ -1,307 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import sys -import os - -from ..extensions import BaseExtensionApp, _get_config_dir, GREEN_ENABLED, RED_DISABLED -from .._version import __version__ -from notebook.config_manager import BaseJSONConfigManager - -from jupyter_core.paths import jupyter_config_path - -from traitlets.utils.importstring import import_item -from traitlets import Bool - -BUNDLER_SECTION = "notebook" -BUNDLER_SUBSECTION = "bundlerextensions" - -def _get_bundler_metadata(module): - """Gets the list of bundlers associated with a Python package. - - Returns a tuple of (the module, [{ - 'name': 'unique name of the bundler', - 'label': 'file menu item label for the bundler', - 'module_name': 'dotted package/module name containing the bundler', - 'group': 'download or deploy parent menu item' - }]) - - Parameters - ---------- - - module : str - Importable Python module exposing the - magic-named `_jupyter_bundlerextension_paths` function - """ - m = import_item(module) - if not hasattr(m, '_jupyter_bundlerextension_paths'): - raise KeyError('The Python module {} does not contain a valid bundlerextension'.format(module)) - bundlers = m._jupyter_bundlerextension_paths() - return m, bundlers - -def _set_bundler_state(name, label, module_name, group, state, - user=True, sys_prefix=False, logger=None): - """Set whether a bundler is enabled or disabled. - - Returns True if the final state is the one requested. - - Parameters - ---------- - name : string - Unique name of the bundler - label : string - Human-readable label for the bundler menu item in the notebook UI - module_name : string - Dotted module/package name containing the bundler - group : string - 'download' or 'deploy' indicating the parent menu containing the label - state : bool - The state in which to leave the extension - user : bool [default: True] - Whether to update the user's .jupyter/nbconfig directory - sys_prefix : bool [default: False] - Whether to update the sys.prefix, i.e. environment. Will override - `user`. - logger : Jupyter logger [optional] - Logger instance to use - """ - user = False if sys_prefix else user - config_dir = os.path.join( - _get_config_dir(user=user, sys_prefix=sys_prefix), 'nbconfig') - cm = BaseJSONConfigManager(config_dir=config_dir) - - if logger: - logger.info("{} {} bundler {}...".format( - "Enabling" if state else "Disabling", - name, - module_name - )) - - if state: - cm.update(BUNDLER_SECTION, { - BUNDLER_SUBSECTION: { - name: { - "label": label, - "module_name": module_name, - "group" : group - } - } - }) - else: - cm.update(BUNDLER_SECTION, { - BUNDLER_SUBSECTION: { - name: None - } - }) - - return (cm.get(BUNDLER_SECTION) - .get(BUNDLER_SUBSECTION, {}) - .get(name) is not None) == state - - -def _set_bundler_state_python(state, module, user, sys_prefix, logger=None): - """Enables or disables bundlers defined in a Python package. - - Returns a list of whether the state was achieved for each bundler. - - Parameters - ---------- - state : Bool - Whether the extensions should be enabled - module : str - Importable Python module exposing the - magic-named `_jupyter_bundlerextension_paths` function - user : bool - Whether to enable in the user's nbconfig directory. - sys_prefix : bool - Enable/disable in the sys.prefix, i.e. environment - logger : Jupyter logger [optional] - Logger instance to use - """ - m, bundlers = _get_bundler_metadata(module) - return [_set_bundler_state(name=bundler["name"], - label=bundler["label"], - module_name=bundler["module_name"], - group=bundler["group"], - state=state, - user=user, sys_prefix=sys_prefix, - logger=logger) - for bundler in bundlers] - -def enable_bundler_python(module, user=True, sys_prefix=False, logger=None): - """Enables bundlers defined in a Python package. - - Returns whether each bundle defined in the packaged was enabled or not. - - Parameters - ---------- - module : str - Importable Python module exposing the - magic-named `_jupyter_bundlerextension_paths` function - user : bool [default: True] - Whether to enable in the user's nbconfig directory. - sys_prefix : bool [default: False] - Whether to enable in the sys.prefix, i.e. environment. Will override - `user` - logger : Jupyter logger [optional] - Logger instance to use - """ - return _set_bundler_state_python(True, module, user, sys_prefix, - logger=logger) - -def disable_bundler_python(module, user=True, sys_prefix=False, logger=None): - """Disables bundlers defined in a Python package. - - Returns whether each bundle defined in the packaged was enabled or not. - - Parameters - ---------- - module : str - Importable Python module exposing the - magic-named `_jupyter_bundlerextension_paths` function - user : bool [default: True] - Whether to enable in the user's nbconfig directory. - sys_prefix : bool [default: False] - Whether to enable in the sys.prefix, i.e. environment. Will override - `user` - logger : Jupyter logger [optional] - Logger instance to use - """ - return _set_bundler_state_python(False, module, user, sys_prefix, - logger=logger) - -class ToggleBundlerExtensionApp(BaseExtensionApp): - """A base class for apps that enable/disable bundlerextensions""" - name = "jupyter bundlerextension enable/disable" - version = __version__ - description = "Enable/disable a bundlerextension in configuration." - - user = Bool(True, config=True, help="Apply the configuration only for the current user (default)") - - _toggle_value = None - - def _config_file_name_default(self): - """The default config file name.""" - return 'jupyter_notebook_config' - - def toggle_bundler_python(self, module): - """Toggle some extensions in an importable Python module. - - Returns a list of booleans indicating whether the state was changed as - requested. - - Parameters - ---------- - module : str - Importable Python module exposing the - magic-named `_jupyter_bundlerextension_paths` function - """ - toggle = (enable_bundler_python if self._toggle_value - else disable_bundler_python) - return toggle(module, - user=self.user, - sys_prefix=self.sys_prefix, - logger=self.log) - - def start(self): - if not self.extra_args: - sys.exit('Please specify an bundlerextension/package to enable or disable') - elif len(self.extra_args) > 1: - sys.exit('Please specify one bundlerextension/package at a time') - if self.python: - self.toggle_bundler_python(self.extra_args[0]) - else: - raise NotImplementedError('Cannot install bundlers from non-Python packages') - -class EnableBundlerExtensionApp(ToggleBundlerExtensionApp): - """An App that enables bundlerextensions""" - name = "jupyter bundlerextension enable" - description = """ - Enable a bundlerextension in frontend configuration. - - Usage - jupyter bundlerextension enable [--system|--sys-prefix] - """ - _toggle_value = True - -class DisableBundlerExtensionApp(ToggleBundlerExtensionApp): - """An App that disables bundlerextensions""" - name = "jupyter bundlerextension disable" - description = """ - Disable a bundlerextension in frontend configuration. - - Usage - jupyter bundlerextension disable [--system|--sys-prefix] - """ - _toggle_value = None - - -class ListBundlerExtensionApp(BaseExtensionApp): - """An App that lists and validates nbextensions""" - name = "jupyter nbextension list" - version = __version__ - description = "List all nbextensions known by the configuration system" - - def list_nbextensions(self): - """List all the nbextensions""" - config_dirs = [os.path.join(p, 'nbconfig') for p in jupyter_config_path()] - - print("Known bundlerextensions:") - - for config_dir in config_dirs: - head = u' config dir: {}'.format(config_dir) - head_shown = False - - cm = BaseJSONConfigManager(parent=self, config_dir=config_dir) - data = cm.get('notebook') - if 'bundlerextensions' in data: - if not head_shown: - # only show heading if there is an nbextension here - print(head) - head_shown = True - - for bundler_id, info in data['bundlerextensions'].items(): - label = info.get('label') - module = info.get('module_name') - if label is None or module is None: - msg = u' {} {}'.format(bundler_id, RED_DISABLED) - else: - msg = u' "{}" from {} {}'.format( - label, module, GREEN_ENABLED - ) - print(msg) - - def start(self): - """Perform the App's functions as configured""" - self.list_nbextensions() - - -class BundlerExtensionApp(BaseExtensionApp): - """Base jupyter bundlerextension command entry point""" - name = "jupyter bundlerextension" - version = __version__ - description = "Work with Jupyter bundler extensions" - examples = """ -jupyter bundlerextension list # list all configured bundlers -jupyter bundlerextension enable --py # enable all bundlers in a Python package -jupyter bundlerextension disable --py # disable all bundlers in a Python package -""" - - subcommands = dict( - enable=(EnableBundlerExtensionApp, "Enable a bundler extension"), - disable=(DisableBundlerExtensionApp, "Disable a bundler extension"), - list=(ListBundlerExtensionApp, "List bundler extensions") - ) - - def start(self): - """Perform the App's functions as configured""" - super().start() - - # The above should have called a subcommand and raised NoStart; if we - # get here, it didn't, so we should self.log.info a message. - subcmds = ", ".join(sorted(self.subcommands)) - sys.exit("Please supply at least one subcommand: %s" % subcmds) - -main = BundlerExtensionApp.launch_instance - -if __name__ == '__main__': - main() diff --git a/notebook/bundler/handlers.py b/notebook/bundler/handlers.py deleted file mode 100644 index 868dd7832..000000000 --- a/notebook/bundler/handlers.py +++ /dev/null @@ -1,88 +0,0 @@ -"""Tornado handler for bundling notebooks.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from ipython_genutils.importstring import import_item -from tornado import web, gen - -from notebook.utils import maybe_future, url2path -from notebook.base.handlers import IPythonHandler -from notebook.services.config import ConfigManager - -from . import tools - - -class BundlerHandler(IPythonHandler): - def initialize(self): - """Make tools module available on the handler instance for compatibility - with existing bundler API and ease of reference.""" - self.tools = tools - - def get_bundler(self, bundler_id): - """ - Get bundler metadata from config given a bundler ID. - - Parameters - ---------- - bundler_id: str - Unique bundler ID within the notebook/bundlerextensions config section - - Returns - ------- - dict - Bundler metadata with label, group, and module_name attributes - - - Raises - ------ - KeyError - If the bundler ID is unknown - """ - cm = ConfigManager() - return cm.get('notebook').get('bundlerextensions', {})[bundler_id] - - @web.authenticated - @gen.coroutine - def get(self, path): - """Bundle the given notebook. - - Parameters - ---------- - path: str - Path to the notebook (path parameter) - bundler: str - Bundler ID to use (query parameter) - """ - bundler_id = self.get_query_argument('bundler') - model = self.contents_manager.get(path=url2path(path)) - - try: - bundler = self.get_bundler(bundler_id) - except KeyError as e: - raise web.HTTPError(400, 'Bundler %s not enabled' % - bundler_id) from e - - module_name = bundler['module_name'] - try: - # no-op in python3, decode error in python2 - module_name = str(module_name) - except UnicodeEncodeError: - # Encode unicode as utf-8 in python2 else import_item fails - module_name = module_name.encode('utf-8') - - try: - bundler_mod = import_item(module_name) - except ImportError as e: - raise web.HTTPError(500, 'Could not import bundler %s ' % - bundler_id) from e - - # Let the bundler respond in any way it sees fit and assume it will - # finish the request - yield maybe_future(bundler_mod.bundle(self, model)) - -_bundler_id_regex = r'(?P[A-Za-z0-9_]+)' - -default_handlers = [ - (r"/bundle/(.*)", BundlerHandler) -] diff --git a/notebook/bundler/tarball_bundler.py b/notebook/bundler/tarball_bundler.py deleted file mode 100644 index c11284148..000000000 --- a/notebook/bundler/tarball_bundler.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os -import io -import tarfile -import nbformat - -def _jupyter_bundlerextension_paths(): - """Metadata for notebook bundlerextension""" - return [{ - # unique bundler name - "name": "tarball_bundler", - # module containing bundle function - "module_name": "notebook.bundler.tarball_bundler", - # human-readable menu item label - "label" : "Notebook Tarball (tar.gz)", - # group under 'deploy' or 'download' menu - "group" : "download", - }] - -def bundle(handler, model): - """Create a compressed tarball containing the notebook document. - - Parameters - ---------- - handler : tornado.web.RequestHandler - Handler that serviced the bundle request - model : dict - Notebook model from the configured ContentManager - """ - notebook_filename = model['name'] - notebook_content = nbformat.writes(model['content']).encode('utf-8') - notebook_name = os.path.splitext(notebook_filename)[0] - tar_filename = '{}.tar.gz'.format(notebook_name) - - info = tarfile.TarInfo(notebook_filename) - info.size = len(notebook_content) - - with io.BytesIO() as tar_buffer: - with tarfile.open(tar_filename, "w:gz", fileobj=tar_buffer) as tar: - tar.addfile(info, io.BytesIO(notebook_content)) - - handler.set_attachment_header(tar_filename) - handler.set_header('Content-Type', 'application/gzip') - - # Return the buffer value as the response - handler.finish(tar_buffer.getvalue()) diff --git a/notebook/bundler/tests/__init__.py b/notebook/bundler/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/bundler/tests/resources/another_subdir/test_file.txt b/notebook/bundler/tests/resources/another_subdir/test_file.txt deleted file mode 100644 index 597cd83d4..000000000 --- a/notebook/bundler/tests/resources/another_subdir/test_file.txt +++ /dev/null @@ -1 +0,0 @@ -Used to test globbing. \ No newline at end of file diff --git a/notebook/bundler/tests/resources/empty.ipynb b/notebook/bundler/tests/resources/empty.ipynb deleted file mode 100644 index bbdd6febf..000000000 --- a/notebook/bundler/tests/resources/empty.ipynb +++ /dev/null @@ -1,6 +0,0 @@ -{ - "nbformat_minor": 0, - "cells": [], - "nbformat": 4, - "metadata": {} -} \ No newline at end of file diff --git a/notebook/bundler/tests/resources/subdir/subsubdir/.gitkeep b/notebook/bundler/tests/resources/subdir/subsubdir/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/bundler/tests/resources/subdir/test_file.txt b/notebook/bundler/tests/resources/subdir/test_file.txt deleted file mode 100644 index 597cd83d4..000000000 --- a/notebook/bundler/tests/resources/subdir/test_file.txt +++ /dev/null @@ -1 +0,0 @@ -Used to test globbing. \ No newline at end of file diff --git a/notebook/bundler/tests/test_bundler_api.py b/notebook/bundler/tests/test_bundler_api.py deleted file mode 100644 index 6c251e5e9..000000000 --- a/notebook/bundler/tests/test_bundler_api.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Test the bundlers API.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import io -from os.path import join as pjoin - -from notebook.tests.launchnotebook import NotebookTestBase -from nbformat import write -from nbformat.v4 import ( - new_notebook, new_markdown_cell, new_code_cell, new_output, -) - -from unittest.mock import patch - - -def bundle(handler, model): - """Bundler test stub. Echo the notebook path.""" - handler.finish(model['path']) - -class BundleAPITest(NotebookTestBase): - """Test the bundlers web service API""" - @classmethod - def setup_class(cls): - """Make a test notebook. Borrowed from nbconvert test. Assumes the class - teardown will clean it up in the end.""" - super(BundleAPITest, cls).setup_class() - nbdir = cls.notebook_dir - - nb = new_notebook() - - nb.cells.append(new_markdown_cell(u'Created by test')) - cc1 = new_code_cell(source=u'print(2*6)') - cc1.outputs.append(new_output(output_type="stream", text=u'12')) - nb.cells.append(cc1) - - with io.open(pjoin(nbdir, 'testnb.ipynb'), 'w', - encoding='utf-8') as f: - write(nb, f, version=4) - - def test_missing_bundler_arg(self): - """Should respond with 400 error about missing bundler arg""" - resp = self.request('GET', 'bundle/fake.ipynb') - self.assertEqual(resp.status_code, 400) - self.assertIn('Missing argument bundler', resp.text) - - def test_notebook_not_found(self): - """Should respond with 404 error about missing notebook""" - resp = self.request('GET', 'bundle/fake.ipynb', - params={'bundler': 'fake_bundler'}) - self.assertEqual(resp.status_code, 404) - self.assertIn('Not Found', resp.text) - - def test_bundler_not_enabled(self): - """Should respond with 400 error about disabled bundler""" - resp = self.request('GET', 'bundle/testnb.ipynb', - params={'bundler': 'fake_bundler'}) - self.assertEqual(resp.status_code, 400) - self.assertIn('Bundler fake_bundler not enabled', resp.text) - - def test_bundler_import_error(self): - """Should respond with 500 error about failure to load bundler module""" - with patch('notebook.bundler.handlers.BundlerHandler.get_bundler') as mock: - mock.return_value = {'module_name': 'fake_module'} - resp = self.request('GET', 'bundle/testnb.ipynb', - params={'bundler': 'fake_bundler'}) - mock.assert_called_with('fake_bundler') - self.assertEqual(resp.status_code, 500) - self.assertIn('Could not import bundler fake_bundler', resp.text) - - def test_bundler_invoke(self): - """Should respond with 200 and output from test bundler stub""" - with patch('notebook.bundler.handlers.BundlerHandler.get_bundler') as mock: - mock.return_value = {'module_name': 'notebook.bundler.tests.test_bundler_api'} - resp = self.request('GET', 'bundle/testnb.ipynb', - params={'bundler': 'stub_bundler'}) - mock.assert_called_with('stub_bundler') - self.assertEqual(resp.status_code, 200) - self.assertIn('testnb.ipynb', resp.text) \ No newline at end of file diff --git a/notebook/bundler/tests/test_bundler_tools.py b/notebook/bundler/tests/test_bundler_tools.py deleted file mode 100644 index 855cf978f..000000000 --- a/notebook/bundler/tests/test_bundler_tools.py +++ /dev/null @@ -1,124 +0,0 @@ -"""Test the bundler tools.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import unittest -import os -import shutil -import tempfile -import notebook.bundler.tools as tools - -HERE = os.path.abspath(os.path.dirname(__file__)) - -class TestBundlerTools(unittest.TestCase): - def setUp(self): - self.tmp = tempfile.mkdtemp() - - def tearDown(self): - shutil.rmtree(self.tmp, ignore_errors=True) - - def test_get_no_cell_references(self): - '''Should find no references in a regular HTML comment.''' - no_references = tools.get_cell_reference_patterns({'source':'''!<-- -a -b -c --->''', 'cell_type':'markdown'}) - self.assertEqual(len(no_references), 0) - - def test_get_cell_reference_patterns_comment_multiline(self): - '''Should find two references and ignore a comment within an HTML comment.''' - cell = {'cell_type':'markdown', 'source':''''''} - references = tools.get_cell_reference_patterns(cell) - self.assertTrue('a' in references and 'b/' in references, str(references)) - self.assertEqual(len(references), 2, str(references)) - - def test_get_cell_reference_patterns_comment_trailing_filename(self): - '''Should find three references within an HTML comment.''' - cell = {'cell_type':'markdown', 'source':''''''} - references = tools.get_cell_reference_patterns(cell) - self.assertTrue('a' in references and 'b/' in references and 'c' in references, str(references)) - self.assertEqual(len(references), 3, str(references)) - - def test_get_cell_reference_patterns_precode(self): - '''Should find no references in a fenced code block in a *code* cell.''' - self.assertTrue(tools.get_cell_reference_patterns) - no_references = tools.get_cell_reference_patterns({'source':'''``` -foo -bar -baz -``` -''', 'cell_type':'code'}) - self.assertEqual(len(no_references), 0) - - def test_get_cell_reference_patterns_precode_mdcomment(self): - '''Should find two references and ignore a comment in a fenced code block.''' - cell = {'cell_type':'markdown', 'source':'''``` -a -b/ -#comment -```'''} - references = tools.get_cell_reference_patterns(cell) - self.assertTrue('a' in references and 'b/' in references, str(references)) - self.assertEqual(len(references), 2, str(references)) - - def test_get_cell_reference_patterns_precode_backticks(self): - '''Should find three references in a fenced code block.''' - cell = {'cell_type':'markdown', 'source':'''```c -a -b/ -#comment -```'''} - references = tools.get_cell_reference_patterns(cell) - self.assertTrue('a' in references and 'b/' in references and 'c' in references, str(references)) - self.assertEqual(len(references), 3, str(references)) - - def test_glob_dir(self): - '''Should expand to single file in the resources/ subfolder.''' - self.assertIn(os.path.join('resources', 'empty.ipynb'), - tools.expand_references(HERE, ['resources/empty.ipynb'])) - - def test_glob_subdir(self): - '''Should expand to all files in the resources/ subfolder.''' - self.assertIn(os.path.join('resources', 'empty.ipynb'), - tools.expand_references(HERE, ['resources/'])) - - def test_glob_splat(self): - '''Should expand to all contents under this test/ directory.''' - globs = tools.expand_references(HERE, ['*']) - self.assertIn('test_bundler_tools.py', globs, globs) - self.assertIn('resources', globs, globs) - - def test_glob_splatsplat_in_middle(self): - '''Should expand to test_file.txt deep under this test/ directory.''' - globs = tools.expand_references(HERE, ['resources/**/test_file.txt']) - self.assertIn(os.path.join('resources', 'subdir', 'test_file.txt'), globs, globs) - - def test_glob_splatsplat_trailing(self): - '''Should expand to all descendants of this test/ directory.''' - globs = tools.expand_references(HERE, ['resources/**']) - self.assertIn(os.path.join('resources', 'empty.ipynb'), globs, globs) - self.assertIn(os.path.join('resources', 'subdir', 'test_file.txt'), globs, globs) - - def test_glob_splatsplat_leading(self): - '''Should expand to test_file.txt under any path.''' - globs = tools.expand_references(HERE, ['**/test_file.txt']) - self.assertIn(os.path.join('resources', 'subdir', 'test_file.txt'), globs, globs) - self.assertIn(os.path.join('resources', 'another_subdir', 'test_file.txt'), globs, globs) - - def test_copy_filelist(self): - '''Should copy select files from source to destination''' - globs = tools.expand_references(HERE, ['**/test_file.txt']) - tools.copy_filelist(HERE, self.tmp, globs) - self.assertTrue(os.path.isfile(os.path.join(self.tmp, 'resources', 'subdir', 'test_file.txt'))) - self.assertTrue(os.path.isfile(os.path.join(self.tmp, 'resources', 'another_subdir', 'test_file.txt'))) - self.assertFalse(os.path.isfile(os.path.join(self.tmp, 'resources', 'empty.ipynb'))) diff --git a/notebook/bundler/tests/test_bundlerextension.py b/notebook/bundler/tests/test_bundlerextension.py deleted file mode 100644 index dcb32424c..000000000 --- a/notebook/bundler/tests/test_bundlerextension.py +++ /dev/null @@ -1,72 +0,0 @@ -"""Test the bundlerextension CLI.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import shutil -import unittest - -from unittest.mock import patch -from ipython_genutils.tempdir import TemporaryDirectory -from ipython_genutils import py3compat - -from traitlets.tests.utils import check_help_all_output - -import notebook.nbextensions as nbextensions -from notebook.config_manager import BaseJSONConfigManager -from ..bundlerextensions import (_get_config_dir, enable_bundler_python, - disable_bundler_python) - -def test_help_output(): - check_help_all_output('notebook.bundler.bundlerextensions') - check_help_all_output('notebook.bundler.bundlerextensions', ['enable']) - check_help_all_output('notebook.bundler.bundlerextensions', ['disable']) - -class TestBundlerExtensionCLI(unittest.TestCase): - """Tests the bundlerextension CLI against the example zip_bundler.""" - def setUp(self): - """Build an isolated config environment.""" - td = TemporaryDirectory() - - self.test_dir = py3compat.cast_unicode(td.name) - self.data_dir = os.path.join(self.test_dir, 'data') - self.config_dir = os.path.join(self.test_dir, 'config') - self.system_data_dir = os.path.join(self.test_dir, 'system_data') - self.system_path = [self.system_data_dir] - - # Use temp directory, not real user or system config paths - self.patch_env = patch.dict('os.environ', { - 'JUPYTER_CONFIG_DIR': self.config_dir, - 'JUPYTER_DATA_DIR': self.data_dir, - }) - self.patch_env.start() - self.patch_system_path = patch.object(nbextensions, - 'SYSTEM_JUPYTER_PATH', self.system_path) - self.patch_system_path.start() - - def tearDown(self): - """Remove the test config environment.""" - shutil.rmtree(self.test_dir, ignore_errors=True) - self.patch_env.stop() - self.patch_system_path.stop() - - def test_enable(self): - """Should add the bundler to the notebook configuration.""" - enable_bundler_python('notebook.bundler.zip_bundler') - - config_dir = os.path.join(_get_config_dir(user=True), 'nbconfig') - cm = BaseJSONConfigManager(config_dir=config_dir) - bundlers = cm.get('notebook').get('bundlerextensions', {}) - self.assertEqual(len(bundlers), 1) - self.assertIn('notebook_zip_download', bundlers) - - def test_disable(self): - """Should remove the bundler from the notebook configuration.""" - self.test_enable() - disable_bundler_python('notebook.bundler.zip_bundler') - - config_dir = os.path.join(_get_config_dir(user=True), 'nbconfig') - cm = BaseJSONConfigManager(config_dir=config_dir) - bundlers = cm.get('notebook').get('bundlerextensions', {}) - self.assertEqual(len(bundlers), 0) diff --git a/notebook/bundler/tools.py b/notebook/bundler/tools.py deleted file mode 100644 index cdf3556ac..000000000 --- a/notebook/bundler/tools.py +++ /dev/null @@ -1,230 +0,0 @@ -"""Set of common tools to aid bundler implementations.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os -import shutil -import errno -import nbformat -import fnmatch -import glob - -def get_file_references(abs_nb_path, version): - """Gets a list of files referenced either in Markdown fenced code blocks - or in HTML comments from the notebook. Expands patterns expressed in - gitignore syntax (https://git-scm.com/docs/gitignore). Returns the - fully expanded list of filenames relative to the notebook dirname. - - Parameters - ---------- - abs_nb_path: str - Absolute path of the notebook on disk - version: int - Version of the notebook document format to use - - Returns - ------- - list - Filename strings relative to the notebook path - """ - ref_patterns = get_reference_patterns(abs_nb_path, version) - expanded = expand_references(os.path.dirname(abs_nb_path), ref_patterns) - return expanded - -def get_reference_patterns(abs_nb_path, version): - """Gets a list of reference patterns either in Markdown fenced code blocks - or in HTML comments from the notebook. - - Parameters - ---------- - abs_nb_path: str - Absolute path of the notebook on disk - version: int - Version of the notebook document format to use - - Returns - ------- - list - Pattern strings from the notebook - """ - notebook = nbformat.read(abs_nb_path, version) - referenced_list = [] - for cell in notebook.cells: - references = get_cell_reference_patterns(cell) - if references: - referenced_list = referenced_list + references - return referenced_list - -def get_cell_reference_patterns(cell): - ''' - Retrieves the list of references from a single notebook cell. Looks for - fenced code blocks or HTML comments in Markdown cells, e.g., - - ``` - some.csv - foo/ - !foo/bar - ``` - - or - - - - Parameters - ---------- - cell: dict - Notebook cell object - - Returns - ------- - list - Reference patterns found in the cell - ''' - referenced = [] - # invisible after execution: unrendered HTML comment - if cell.get('cell_type').startswith('markdown') and cell.get('source').startswith(''): - break - # Trying to go out of the current directory leads to - # trouble when deploying - if line.find('../') < 0 and not line.startswith('#'): - referenced.append(line) - # visible after execution: rendered as a code element within a pre element - elif cell.get('cell_type').startswith('markdown') and cell.get('source').find('```') >= 0: - source = cell.get('source') - offset = source.find('```') - lines = source[offset + len('```'):].splitlines() - for line in lines: - if line.startswith('```'): - break - # Trying to go out of the current directory leads to - # trouble when deploying - if line.find('../') < 0 and not line.startswith('#'): - referenced.append(line) - - # Clean out blank references - return [ref for ref in referenced if ref.strip()] - -def expand_references(root_path, references): - """Expands a set of reference patterns by evaluating them against the - given root directory. Expansions are performed against patterns - expressed in the same manner as in gitignore - (https://git-scm.com/docs/gitignore). - - NOTE: Temporarily changes the current working directory when called. - - Parameters - ---------- - root_path: str - Assumed root directory for the patterns - references: list - Reference patterns from get_reference_patterns expressed with - forward-slash directory separators - - Returns - ------- - list - Filename strings relative to the root path - """ - # Use normpath to convert to platform specific slashes, but be sure - # to retain a trailing slash which normpath pulls off - normalized_references = [] - for ref in references: - normalized_ref = os.path.normpath(ref) - # un-normalized separator - if ref.endswith('/'): - normalized_ref += os.sep - normalized_references.append(normalized_ref) - references = normalized_references - - globbed = [] - negations = [] - must_walk = [] - for pattern in references: - if pattern and pattern.find(os.sep) < 0: - # simple shell glob - cwd = os.getcwd() - os.chdir(root_path) - if pattern.startswith('!'): - negations = negations + glob.glob(pattern[1:]) - else: - globbed = globbed + glob.glob(pattern) - os.chdir(cwd) - elif pattern: - must_walk.append(pattern) - - for pattern in must_walk: - pattern_is_negation = pattern.startswith('!') - if pattern_is_negation: - testpattern = pattern[1:] - else: - testpattern = pattern - for root, _, filenames in os.walk(root_path): - for filename in filenames: - joined = os.path.join(root[len(root_path) + 1:], filename) - if testpattern.endswith(os.sep): - if joined.startswith(testpattern): - if pattern_is_negation: - negations.append(joined) - else: - globbed.append(joined) - elif testpattern.find('**') >= 0: - # path wildcard - ends = testpattern.split('**') - if len(ends) == 2: - if joined.startswith(ends[0]) and joined.endswith(ends[1]): - if pattern_is_negation: - negations.append(joined) - else: - globbed.append(joined) - else: - # segments should be respected - if fnmatch.fnmatch(joined, testpattern): - if pattern_is_negation: - negations.append(joined) - else: - globbed.append(joined) - - for negated in negations: - try: - globbed.remove(negated) - except ValueError as err: - pass - return set(globbed) - -def copy_filelist(src, dst, src_relative_filenames): - """Copies the given list of files, relative to src, into dst, creating - directories along the way as needed and ignore existence errors. - Skips any files that do not exist. Does not create empty directories - from src in dst. - - Parameters - ---------- - src: str - Root of the source directory - dst: str - Root of the destination directory - src_relative_filenames: list - Filenames relative to src - """ - for filename in src_relative_filenames: - # Only consider the file if it exists in src - if os.path.isfile(os.path.join(src, filename)): - parent_relative = os.path.dirname(filename) - if parent_relative: - # Make sure the parent directory exists - parent_dst = os.path.join(dst, parent_relative) - try: - os.makedirs(parent_dst) - except OSError as exc: - if exc.errno == errno.EEXIST: - pass - else: - raise exc - shutil.copy2(os.path.join(src, filename), os.path.join(dst, filename)) diff --git a/notebook/bundler/zip_bundler.py b/notebook/bundler/zip_bundler.py deleted file mode 100644 index f7bd5cc7a..000000000 --- a/notebook/bundler/zip_bundler.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import os -import io -import zipfile -import notebook.bundler.tools as tools - -def _jupyter_bundlerextension_paths(): - """Metadata for notebook bundlerextension""" - return [{ - 'name': 'notebook_zip_download', - 'label': 'IPython Notebook bundle (.zip)', - 'module_name': 'notebook.bundler.zip_bundler', - 'group': 'download' - }] - -def bundle(handler, model): - """Create a zip file containing the original notebook and files referenced - from it. Retain the referenced files in paths relative to the notebook. - Return the zip as a file download. - - Assumes the notebook and other files are all on local disk. - - Parameters - ---------- - handler : tornado.web.RequestHandler - Handler that serviced the bundle request - model : dict - Notebook model from the configured ContentManager - """ - abs_nb_path = os.path.join(handler.settings['contents_manager'].root_dir, - model['path']) - notebook_filename = model['name'] - notebook_name = os.path.splitext(notebook_filename)[0] - - # Headers - zip_filename = os.path.splitext(notebook_name)[0] + '.zip' - handler.set_attachment_header(zip_filename) - handler.set_header('Content-Type', 'application/zip') - - # Get associated files - ref_filenames = tools.get_file_references(abs_nb_path, 4) - - # Prepare the zip file - zip_buffer = io.BytesIO() - zipf = zipfile.ZipFile(zip_buffer, mode='w', compression=zipfile.ZIP_DEFLATED) - zipf.write(abs_nb_path, notebook_filename) - - notebook_dir = os.path.dirname(abs_nb_path) - for nb_relative_filename in ref_filenames: - # Build absolute path to file on disk - abs_fn = os.path.join(notebook_dir, nb_relative_filename) - # Store file under path relative to notebook - zipf.write(abs_fn, nb_relative_filename) - - zipf.close() - - # Return the buffer value as the response - handler.finish(zip_buffer.getvalue()) \ No newline at end of file diff --git a/notebook/config_manager.py b/notebook/config_manager.py deleted file mode 100644 index 137cbd691..000000000 --- a/notebook/config_manager.py +++ /dev/null @@ -1,132 +0,0 @@ -"""Manager to read and modify config data in JSON files.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import errno -import glob -import io -import json -import os -import copy - -from traitlets.config import LoggingConfigurable -from traitlets.traitlets import Unicode, Bool - - -def recursive_update(target, new): - """Recursively update one dictionary using another. - - None values will delete their keys. - """ - for k, v in new.items(): - if isinstance(v, dict): - if k not in target: - target[k] = {} - recursive_update(target[k], v) - if not target[k]: - # Prune empty subdicts - del target[k] - - elif v is None: - target.pop(k, None) - - else: - target[k] = v - - -def remove_defaults(data, defaults): - """Recursively remove items from dict that are already in defaults""" - # copy the iterator, since data will be modified - for key, value in list(data.items()): - if key in defaults: - if isinstance(value, dict): - remove_defaults(data[key], defaults[key]) - if not data[key]: # prune empty subdicts - del data[key] - else: - if value == defaults[key]: - del data[key] - - -class BaseJSONConfigManager(LoggingConfigurable): - """General JSON config manager - - Deals with persisting/storing config in a json file with optionally - default values in a {section_name}.d directory. - """ - - config_dir = Unicode('.') - read_directory = Bool(True) - - def ensure_config_dir_exists(self): - """Will try to create the config_dir directory.""" - try: - os.makedirs(self.config_dir, 0o755) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - def file_name(self, section_name): - """Returns the json filename for the section_name: {config_dir}/{section_name}.json""" - return os.path.join(self.config_dir, section_name+'.json') - - def directory(self, section_name): - """Returns the directory name for the section name: {config_dir}/{section_name}.d""" - return os.path.join(self.config_dir, section_name+'.d') - - def get(self, section_name, include_root=True): - """Retrieve the config data for the specified section. - - Returns the data as a dictionary, or an empty dictionary if the file - doesn't exist. - - When include_root is False, it will not read the root .json file, - effectively returning the default values. - """ - paths = [self.file_name(section_name)] if include_root else [] - if self.read_directory: - pattern = os.path.join(self.directory(section_name), '*.json') - # These json files should be processed first so that the - # {section_name}.json take precedence. - # The idea behind this is that installing a Python package may - # put a json file somewhere in the a .d directory, while the - # .json file is probably a user configuration. - paths = sorted(glob.glob(pattern)) + paths - self.log.debug('Paths used for configuration of %s: \n\t%s', section_name, '\n\t'.join(paths)) - data = {} - for path in paths: - if os.path.isfile(path): - with io.open(path, encoding='utf-8') as f: - recursive_update(data, json.load(f)) - return data - - def set(self, section_name, data): - """Store the given config data. - """ - filename = self.file_name(section_name) - self.ensure_config_dir_exists() - - if self.read_directory: - # we will modify data in place, so make a copy - data = copy.deepcopy(data) - defaults = self.get(section_name, include_root=False) - remove_defaults(data, defaults) - - # Generate the JSON up front, since it could raise an exception, - # in order to avoid writing half-finished corrupted data to disk. - json_content = json.dumps(data, indent=2) - - f = io.open(filename, 'w', encoding='utf-8') - with f: - f.write(json_content) - - def update(self, section_name, new_data): - """Modify the config section by recursively updating it with new_data. - - Returns the modified config data as a dictionary. - """ - data = self.get(section_name) - recursive_update(data, new_data) - self.set(section_name, data) - return data diff --git a/notebook/edit/__init__.py b/notebook/edit/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/edit/handlers.py b/notebook/edit/handlers.py deleted file mode 100644 index 9ed9a9c38..000000000 --- a/notebook/edit/handlers.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Tornado handlers for the terminal emulator.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from tornado import web -from ..base.handlers import IPythonHandler, path_regex -from ..utils import url_escape - -class EditorHandler(IPythonHandler): - """Render the text editor interface.""" - @web.authenticated - def get(self, path): - path = path.strip('/') - if not self.contents_manager.file_exists(path): - raise web.HTTPError(404, u'File does not exist: %s' % path) - - basename = path.rsplit('/', 1)[-1] - self.write(self.render_template('edit.html', - file_path=url_escape(path), - basename=basename, - page_title=basename + " (editing)", - ) - ) - -default_handlers = [ - (r"/edit%s" % path_regex, EditorHandler), -] \ No newline at end of file diff --git a/notebook/extensions.py b/notebook/extensions.py deleted file mode 100644 index 8efa65724..000000000 --- a/notebook/extensions.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Utilities for installing extensions""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -from tornado.log import LogFormatter -from traitlets import Bool, Any -from jupyter_core.application import JupyterApp -from jupyter_core.paths import ( - jupyter_config_dir, ENV_CONFIG_PATH, SYSTEM_CONFIG_PATH -) -from ._version import __version__ - -class ArgumentConflict(ValueError): - pass - -_base_flags = {} -_base_flags.update(JupyterApp.flags) -_base_flags.pop("y", None) -_base_flags.pop("generate-config", None) -_base_flags.update({ - "user" : ({ - "BaseExtensionApp" : { - "user" : True, - }}, "Apply the operation only for the given user" - ), - "system" : ({ - "BaseExtensionApp" : { - "user" : False, - "sys_prefix": False, - }}, "Apply the operation system-wide" - ), - "sys-prefix" : ({ - "BaseExtensionApp" : { - "sys_prefix" : True, - }}, "Use sys.prefix as the prefix for installing nbextensions (for environments, packaging)" - ), - "py" : ({ - "BaseExtensionApp" : { - "python" : True, - }}, "Install from a Python package" - ) -}) -_base_flags['python'] = _base_flags['py'] - -_base_aliases = {} -_base_aliases.update(JupyterApp.aliases) - - -class BaseExtensionApp(JupyterApp): - """Base nbextension installer app""" - _log_formatter_cls = LogFormatter - flags = _base_flags - aliases = _base_aliases - version = __version__ - - user = Bool(False, config=True, help="Whether to do a user install") - sys_prefix = Bool(False, config=True, help="Use the sys.prefix as the prefix") - python = Bool(False, config=True, help="Install from a Python package") - - # Remove for 5.0... - verbose = Any(None, config=True, help="DEPRECATED: Verbosity level") - - def _verbose_changed(self): - """Warn about verbosity changes""" - import warnings - warnings.warn("`verbose` traits of `{}` has been deprecated, has no effects and will be removed in notebook 5.0.".format(type(self).__name__), DeprecationWarning) - - def _log_format_default(self): - """A default format for messages""" - return "%(message)s" - -def _get_config_dir(user=False, sys_prefix=False): - """Get the location of config files for the current context - - Returns the string to the environment - - Parameters - ---------- - - user : bool [default: False] - Get the user's .jupyter config directory - sys_prefix : bool [default: False] - Get sys.prefix, i.e. ~/.envs/my-env/etc/jupyter - """ - user = False if sys_prefix else user - if user and sys_prefix: - raise ArgumentConflict("Cannot specify more than one of user or sys_prefix") - if user: - nbext = jupyter_config_dir() - elif sys_prefix: - nbext = ENV_CONFIG_PATH[0] - else: - nbext = SYSTEM_CONFIG_PATH[0] - return nbext - -# Constants for pretty print extension listing function. -# Window doesn't support coloring in the commandline -GREEN_ENABLED = '\033[32m enabled \033[0m' if os.name != 'nt' else 'enabled ' -RED_DISABLED = '\033[31mdisabled\033[0m' if os.name != 'nt' else 'disabled' -GREEN_OK = '\033[32mOK\033[0m' if os.name != 'nt' else 'ok' -RED_X = '\033[31m X\033[0m' if os.name != 'nt' else ' X' diff --git a/notebook/files/__init__.py b/notebook/files/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/files/handlers.py b/notebook/files/handlers.py deleted file mode 100644 index b412cd84e..000000000 --- a/notebook/files/handlers.py +++ /dev/null @@ -1,84 +0,0 @@ -"""Serve files directly from the ContentsManager.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import mimetypes -import json -from base64 import decodebytes - -from tornado import gen, web - -from notebook.base.handlers import IPythonHandler -from notebook.utils import maybe_future - - -class FilesHandler(IPythonHandler): - """serve files via ContentsManager - - Normally used when ContentsManager is not a FileContentsManager. - - FileContentsManager subclasses use AuthenticatedFilesHandler by default, - a subclass of StaticFileHandler. - """ - - @property - def content_security_policy(self): - # In case we're serving HTML/SVG, confine any Javascript to a unique - # origin so it can't interact with the notebook server. - return super().content_security_policy + "; sandbox allow-scripts" - - @web.authenticated - def head(self, path): - self.check_xsrf_cookie() - return self.get(path, include_body=False) - - @web.authenticated - @gen.coroutine - def get(self, path, include_body=True): - # /files/ requests must originate from the same site - self.check_xsrf_cookie() - cm = self.contents_manager - - if cm.is_hidden(path) and not cm.allow_hidden: - self.log.info("Refusing to serve hidden file, via 404 Error") - raise web.HTTPError(404) - - path = path.strip('/') - if '/' in path: - _, name = path.rsplit('/', 1) - else: - name = path - - model = yield maybe_future(cm.get(path, type='file', content=include_body)) - - if self.get_argument("download", False): - self.set_attachment_header(name) - - # get mimetype from filename - if name.lower().endswith('.ipynb'): - self.set_header('Content-Type', 'application/x-ipynb+json') - else: - cur_mime = mimetypes.guess_type(name)[0] - if cur_mime == 'text/plain': - self.set_header('Content-Type', 'text/plain; charset=UTF-8') - elif cur_mime is not None: - self.set_header('Content-Type', cur_mime) - else: - if model['format'] == 'base64': - self.set_header('Content-Type', 'application/octet-stream') - else: - self.set_header('Content-Type', 'text/plain; charset=UTF-8') - - if include_body: - if model['format'] == 'base64': - b64_bytes = model['content'].encode('ascii') - self.write(decodebytes(b64_bytes)) - elif model['format'] == 'json': - self.write(json.dumps(model['content'])) - else: - self.write(model['content']) - self.flush() - - -default_handlers = [] diff --git a/notebook/gateway/__init__.py b/notebook/gateway/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/gateway/handlers.py b/notebook/gateway/handlers.py deleted file mode 100644 index d774ba39e..000000000 --- a/notebook/gateway/handlers.py +++ /dev/null @@ -1,263 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import logging -import mimetypes -import random - -from ..base.handlers import APIHandler, IPythonHandler -from ..utils import url_path_join - -from tornado import gen, web -from tornado.concurrent import Future -from tornado.ioloop import IOLoop, PeriodicCallback -from tornado.websocket import WebSocketHandler, websocket_connect -from tornado.httpclient import HTTPRequest -from tornado.escape import url_escape, json_decode, utf8 - -from ipython_genutils.py3compat import cast_unicode -from jupyter_client.session import Session -from traitlets.config.configurable import LoggingConfigurable - -from .managers import GatewayClient - -# Keepalive ping interval (default: 30 seconds) -GATEWAY_WS_PING_INTERVAL_SECS = int(os.getenv('GATEWAY_WS_PING_INTERVAL_SECS', 30)) - - -class WebSocketChannelsHandler(WebSocketHandler, IPythonHandler): - - session = None - gateway = None - kernel_id = None - ping_callback = None - - def check_origin(self, origin=None): - return IPythonHandler.check_origin(self, origin) - - def set_default_headers(self): - """Undo the set_default_headers in IPythonHandler which doesn't make sense for websockets""" - pass - - def get_compression_options(self): - # use deflate compress websocket - return {} - - def authenticate(self): - """Run before finishing the GET request - - Extend this method to add logic that should fire before - the websocket finishes completing. - """ - # authenticate the request before opening the websocket - if self.get_current_user() is None: - self.log.warning("Couldn't authenticate WebSocket connection") - raise web.HTTPError(403) - - if self.get_argument('session_id', False): - self.session.session = cast_unicode(self.get_argument('session_id')) - else: - self.log.warning("No session ID specified") - - def initialize(self): - self.log.debug("Initializing websocket connection %s", self.request.path) - self.session = Session(config=self.config) - self.gateway = GatewayWebSocketClient(gateway_url=GatewayClient.instance().url) - - @gen.coroutine - def get(self, kernel_id, *args, **kwargs): - self.authenticate() - self.kernel_id = cast_unicode(kernel_id, 'ascii') - yield super().get(kernel_id=kernel_id, *args, **kwargs) - - def send_ping(self): - if self.ws_connection is None and self.ping_callback is not None: - self.ping_callback.stop() - return - - self.ping(b'') - - def open(self, kernel_id, *args, **kwargs): - """Handle web socket connection open to notebook server and delegate to gateway web socket handler """ - self.ping_callback = PeriodicCallback(self.send_ping, GATEWAY_WS_PING_INTERVAL_SECS * 1000) - self.ping_callback.start() - - self.gateway.on_open( - kernel_id=kernel_id, - message_callback=self.write_message, - compression_options=self.get_compression_options() - ) - - def on_message(self, message): - """Forward message to gateway web socket handler.""" - self.gateway.on_message(message) - - def write_message(self, message, binary=False): - """Send message back to notebook client. This is called via callback from self.gateway._read_messages.""" - if self.ws_connection: # prevent WebSocketClosedError - if isinstance(message, bytes): - binary = True - super().write_message(message, binary=binary) - elif self.log.isEnabledFor(logging.DEBUG): - msg_summary = WebSocketChannelsHandler._get_message_summary(json_decode(utf8(message))) - self.log.debug("Notebook client closed websocket connection - message dropped: {}".format(msg_summary)) - - def on_close(self): - self.log.debug("Closing websocket connection %s", self.request.path) - self.gateway.on_close() - super().on_close() - - @staticmethod - def _get_message_summary(message): - summary = [] - message_type = message['msg_type'] - summary.append('type: {}'.format(message_type)) - - if message_type == 'status': - summary.append(', state: {}'.format(message['content']['execution_state'])) - elif message_type == 'error': - summary.append(', {}:{}:{}'.format(message['content']['ename'], - message['content']['evalue'], - message['content']['traceback'])) - else: - summary.append(', ...') # don't display potentially sensitive data - - return ''.join(summary) - - -class GatewayWebSocketClient(LoggingConfigurable): - """Proxy web socket connection to a kernel/enterprise gateway.""" - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.kernel_id = None - self.ws = None - self.ws_future = Future() - self.disconnected = False - self.retry = 0 - - @gen.coroutine - def _connect(self, kernel_id): - # websocket is initialized before connection - self.ws = None - self.kernel_id = kernel_id - ws_url = url_path_join( - GatewayClient.instance().ws_url, - GatewayClient.instance().kernels_endpoint, url_escape(kernel_id), 'channels' - ) - self.log.info('Connecting to {}'.format(ws_url)) - kwargs = {} - kwargs = GatewayClient.instance().load_connection_args(**kwargs) - - request = HTTPRequest(ws_url, **kwargs) - self.ws_future = websocket_connect(request) - self.ws_future.add_done_callback(self._connection_done) - - def _connection_done(self, fut): - if not self.disconnected and fut.exception() is None: # prevent concurrent.futures._base.CancelledError - self.ws = fut.result() - self.retry = 0 - self.log.debug("Connection is ready: ws: {}".format(self.ws)) - else: - self.log.warning("Websocket connection has been closed via client disconnect or due to error. " - "Kernel with ID '{}' may not be terminated on GatewayClient: {}". - format(self.kernel_id, GatewayClient.instance().url)) - - def _disconnect(self): - self.disconnected = True - if self.ws is not None: - # Close connection - self.ws.close() - elif not self.ws_future.done(): - # Cancel pending connection. Since future.cancel() is a noop on tornado, we'll track cancellation locally - self.ws_future.cancel() - self.log.debug("_disconnect: future cancelled, disconnected: {}".format(self.disconnected)) - - @gen.coroutine - def _read_messages(self, callback): - """Read messages from gateway server.""" - while self.ws is not None: - message = None - if not self.disconnected: - try: - message = yield self.ws.read_message() - except Exception as e: - self.log.error("Exception reading message from websocket: {}".format(e)) # , exc_info=True) - if message is None: - if not self.disconnected: - self.log.warning("Lost connection to Gateway: {}".format(self.kernel_id)) - break - callback(message) # pass back to notebook client (see self.on_open and WebSocketChannelsHandler.open) - else: # ws cancelled - stop reading - break - - # NOTE(esevan): if websocket is not disconnected by client, try to reconnect. - if not self.disconnected and self.retry < GatewayClient.instance().gateway_retry_max: - jitter = random.randint(10, 100) * 0.01 - retry_interval = min(GatewayClient.instance().gateway_retry_interval * (2 ** self.retry), - GatewayClient.instance().gateway_retry_interval_max) + jitter - self.retry += 1 - self.log.info("Attempting to re-establish the connection to Gateway in %s secs (%s/%s): %s", - retry_interval, self.retry, GatewayClient.instance().gateway_retry_max, self.kernel_id) - yield gen.sleep(retry_interval) - self._connect(self.kernel_id) - loop = IOLoop.current() - loop.add_future(self.ws_future, lambda future: self._read_messages(callback)) - - def on_open(self, kernel_id, message_callback, **kwargs): - """Web socket connection open against gateway server.""" - self._connect(kernel_id) - loop = IOLoop.current() - loop.add_future( - self.ws_future, - lambda future: self._read_messages(message_callback) - ) - - def on_message(self, message): - """Send message to gateway server.""" - if self.ws is None: - loop = IOLoop.current() - loop.add_future( - self.ws_future, - lambda future: self._write_message(message) - ) - else: - self._write_message(message) - - def _write_message(self, message): - """Send message to gateway server.""" - try: - if not self.disconnected and self.ws is not None: - self.ws.write_message(message) - except Exception as e: - self.log.error("Exception writing message to websocket: {}".format(e)) # , exc_info=True) - - def on_close(self): - """Web socket closed event.""" - self._disconnect() - - -class GatewayResourceHandler(APIHandler): - """Retrieves resources for specific kernelspec definitions from kernel/enterprise gateway.""" - - @web.authenticated - @gen.coroutine - def get(self, kernel_name, path, include_body=True): - ksm = self.kernel_spec_manager - kernel_spec_res = yield ksm.get_kernel_spec_resource(kernel_name, path) - if kernel_spec_res is None: - self.log.warning("Kernelspec resource '{}' for '{}' not found. Gateway may not support" - " resource serving.".format(path, kernel_name)) - else: - self.set_header("Content-Type", mimetypes.guess_type(path)[0]) - self.finish(kernel_spec_res) - - -from ..services.kernels.handlers import _kernel_id_regex -from ..services.kernelspecs.handlers import kernel_name_regex - -default_handlers = [ - (r"/api/kernels/%s/channels" % _kernel_id_regex, WebSocketChannelsHandler), - (r"/kernelspecs/%s/(?P.*)" % kernel_name_regex, GatewayResourceHandler), -] diff --git a/notebook/gateway/managers.py b/notebook/gateway/managers.py deleted file mode 100644 index b2ae3b30a..000000000 --- a/notebook/gateway/managers.py +++ /dev/null @@ -1,662 +0,0 @@ -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import json - -from socket import gaierror -from tornado import web -from tornado.escape import json_encode, json_decode, url_escape -from tornado.httpclient import HTTPClient, AsyncHTTPClient, HTTPError - -from ..services.kernels.kernelmanager import AsyncMappingKernelManager -from ..services.sessions.sessionmanager import SessionManager - -from jupyter_client.kernelspec import KernelSpecManager -from ..utils import url_path_join - -from traitlets import Instance, Unicode, Int, Float, Bool, default, validate, TraitError -from traitlets.config import SingletonConfigurable - - -class GatewayClient(SingletonConfigurable): - """This class manages the configuration. It's its own singleton class so that we - can share these values across all objects. It also contains some helper methods - to build request arguments out of the various config options. - - """ - - url = Unicode(default_value=None, allow_none=True, config=True, - help="""The url of the Kernel or Enterprise Gateway server where - kernel specifications are defined and kernel management takes place. - If defined, this Notebook server acts as a proxy for all kernel - management and kernel specification retrieval. (JUPYTER_GATEWAY_URL env var) - """ - ) - - url_env = 'JUPYTER_GATEWAY_URL' - - @default('url') - def _url_default(self): - return os.environ.get(self.url_env) - - @validate('url') - def _url_validate(self, proposal): - value = proposal['value'] - # Ensure value, if present, starts with 'http' - if value is not None and len(value) > 0: - if not str(value).lower().startswith('http'): - raise TraitError("GatewayClient url must start with 'http': '%r'" % value) - return value - - ws_url = Unicode(default_value=None, allow_none=True, config=True, - help="""The websocket url of the Kernel or Enterprise Gateway server. If not provided, this value - will correspond to the value of the Gateway url with 'ws' in place of 'http'. (JUPYTER_GATEWAY_WS_URL env var) - """ - ) - - ws_url_env = 'JUPYTER_GATEWAY_WS_URL' - - @default('ws_url') - def _ws_url_default(self): - default_value = os.environ.get(self.ws_url_env) - if default_value is None: - if self.gateway_enabled: - default_value = self.url.lower().replace('http', 'ws') - return default_value - - @validate('ws_url') - def _ws_url_validate(self, proposal): - value = proposal['value'] - # Ensure value, if present, starts with 'ws' - if value is not None and len(value) > 0: - if not str(value).lower().startswith('ws'): - raise TraitError("GatewayClient ws_url must start with 'ws': '%r'" % value) - return value - - kernels_endpoint_default_value = '/api/kernels' - kernels_endpoint_env = 'JUPYTER_GATEWAY_KERNELS_ENDPOINT' - kernels_endpoint = Unicode(default_value=kernels_endpoint_default_value, config=True, - help="""The gateway API endpoint for accessing kernel resources (JUPYTER_GATEWAY_KERNELS_ENDPOINT env var)""") - - @default('kernels_endpoint') - def _kernels_endpoint_default(self): - return os.environ.get(self.kernels_endpoint_env, self.kernels_endpoint_default_value) - - kernelspecs_endpoint_default_value = '/api/kernelspecs' - kernelspecs_endpoint_env = 'JUPYTER_GATEWAY_KERNELSPECS_ENDPOINT' - kernelspecs_endpoint = Unicode(default_value=kernelspecs_endpoint_default_value, config=True, - help="""The gateway API endpoint for accessing kernelspecs (JUPYTER_GATEWAY_KERNELSPECS_ENDPOINT env var)""") - - @default('kernelspecs_endpoint') - def _kernelspecs_endpoint_default(self): - return os.environ.get(self.kernelspecs_endpoint_env, self.kernelspecs_endpoint_default_value) - - kernelspecs_resource_endpoint_default_value = '/kernelspecs' - kernelspecs_resource_endpoint_env = 'JUPYTER_GATEWAY_KERNELSPECS_RESOURCE_ENDPOINT' - kernelspecs_resource_endpoint = Unicode(default_value=kernelspecs_resource_endpoint_default_value, config=True, - help="""The gateway endpoint for accessing kernelspecs resources - (JUPYTER_GATEWAY_KERNELSPECS_RESOURCE_ENDPOINT env var)""") - - @default('kernelspecs_resource_endpoint') - def _kernelspecs_resource_endpoint_default(self): - return os.environ.get(self.kernelspecs_resource_endpoint_env, self.kernelspecs_resource_endpoint_default_value) - - connect_timeout_default_value = 40.0 - connect_timeout_env = 'JUPYTER_GATEWAY_CONNECT_TIMEOUT' - connect_timeout = Float(default_value=connect_timeout_default_value, config=True, - help="""The time allowed for HTTP connection establishment with the Gateway server. - (JUPYTER_GATEWAY_CONNECT_TIMEOUT env var)""") - - @default('connect_timeout') - def connect_timeout_default(self): - return float(os.environ.get('JUPYTER_GATEWAY_CONNECT_TIMEOUT', self.connect_timeout_default_value)) - - request_timeout_default_value = 40.0 - request_timeout_env = 'JUPYTER_GATEWAY_REQUEST_TIMEOUT' - request_timeout = Float(default_value=request_timeout_default_value, config=True, - help="""The time allowed for HTTP request completion. (JUPYTER_GATEWAY_REQUEST_TIMEOUT env var)""") - - @default('request_timeout') - def request_timeout_default(self): - return float(os.environ.get('JUPYTER_GATEWAY_REQUEST_TIMEOUT', self.request_timeout_default_value)) - - client_key = Unicode(default_value=None, allow_none=True, config=True, - help="""The filename for client SSL key, if any. (JUPYTER_GATEWAY_CLIENT_KEY env var) - """ - ) - client_key_env = 'JUPYTER_GATEWAY_CLIENT_KEY' - - @default('client_key') - def _client_key_default(self): - return os.environ.get(self.client_key_env) - - client_cert = Unicode(default_value=None, allow_none=True, config=True, - help="""The filename for client SSL certificate, if any. (JUPYTER_GATEWAY_CLIENT_CERT env var) - """ - ) - client_cert_env = 'JUPYTER_GATEWAY_CLIENT_CERT' - - @default('client_cert') - def _client_cert_default(self): - return os.environ.get(self.client_cert_env) - - ca_certs = Unicode(default_value=None, allow_none=True, config=True, - help="""The filename of CA certificates or None to use defaults. (JUPYTER_GATEWAY_CA_CERTS env var) - """ - ) - ca_certs_env = 'JUPYTER_GATEWAY_CA_CERTS' - - @default('ca_certs') - def _ca_certs_default(self): - return os.environ.get(self.ca_certs_env) - - http_user = Unicode(default_value=None, allow_none=True, config=True, - help="""The username for HTTP authentication. (JUPYTER_GATEWAY_HTTP_USER env var) - """ - ) - http_user_env = 'JUPYTER_GATEWAY_HTTP_USER' - - @default('http_user') - def _http_user_default(self): - return os.environ.get(self.http_user_env) - - http_pwd = Unicode(default_value=None, allow_none=True, config=True, - help="""The password for HTTP authentication. (JUPYTER_GATEWAY_HTTP_PWD env var) - """ - ) - http_pwd_env = 'JUPYTER_GATEWAY_HTTP_PWD' - - @default('http_pwd') - def _http_pwd_default(self): - return os.environ.get(self.http_pwd_env) - - headers_default_value = '{}' - headers_env = 'JUPYTER_GATEWAY_HEADERS' - headers = Unicode(default_value=headers_default_value, allow_none=True, config=True, - help="""Additional HTTP headers to pass on the request. This value will be converted to a dict. - (JUPYTER_GATEWAY_HEADERS env var) - """ - ) - - @default('headers') - def _headers_default(self): - return os.environ.get(self.headers_env, self.headers_default_value) - - auth_token = Unicode(default_value=None, allow_none=True, config=True, - help="""The authorization token used in the HTTP headers. (JUPYTER_GATEWAY_AUTH_TOKEN env var) - """ - ) - auth_token_env = 'JUPYTER_GATEWAY_AUTH_TOKEN' - - @default('auth_token') - def _auth_token_default(self): - return os.environ.get(self.auth_token_env, '') - - validate_cert_default_value = True - validate_cert_env = 'JUPYTER_GATEWAY_VALIDATE_CERT' - validate_cert = Bool(default_value=validate_cert_default_value, config=True, - help="""For HTTPS requests, determines if server's certificate should be validated or not. - (JUPYTER_GATEWAY_VALIDATE_CERT env var)""" - ) - - @default('validate_cert') - def validate_cert_default(self): - return bool(os.environ.get(self.validate_cert_env, str(self.validate_cert_default_value)) not in ['no', 'false']) - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self._static_args = {} # initialized on first use - - env_whitelist_default_value = '' - env_whitelist_env = 'JUPYTER_GATEWAY_ENV_WHITELIST' - env_whitelist = Unicode(default_value=env_whitelist_default_value, config=True, - help="""A comma-separated list of environment variable names that will be included, along with - their values, in the kernel startup request. The corresponding `env_whitelist` configuration - value must also be set on the Gateway server - since that configuration value indicates which - environmental values to make available to the kernel. (JUPYTER_GATEWAY_ENV_WHITELIST env var)""") - - @default('env_whitelist') - def _env_whitelist_default(self): - return os.environ.get(self.env_whitelist_env, self.env_whitelist_default_value) - - gateway_retry_interval_default_value = 1.0 - gateway_retry_interval_env = 'JUPYTER_GATEWAY_RETRY_INTERVAL' - gateway_retry_interval = Float(default_value=gateway_retry_interval_default_value, config=True, - help="""The time allowed for HTTP reconnection with the Gateway server for the first time. - Next will be JUPYTER_GATEWAY_RETRY_INTERVAL multiplied by two in factor of numbers of retries - but less than JUPYTER_GATEWAY_RETRY_INTERVAL_MAX. - (JUPYTER_GATEWAY_RETRY_INTERVAL env var)""") - - @default('gateway_retry_interval') - def gateway_retry_interval_default(self): - return float(os.environ.get('JUPYTER_GATEWAY_RETRY_INTERVAL', self.gateway_retry_interval_default_value)) - - gateway_retry_interval_max_default_value = 30.0 - gateway_retry_interval_max_env = 'JUPYTER_GATEWAY_RETRY_INTERVAL_MAX' - gateway_retry_interval_max = Float(default_value=gateway_retry_interval_max_default_value, config=True, - help="""The maximum time allowed for HTTP reconnection retry with the Gateway server. - (JUPYTER_GATEWAY_RETRY_INTERVAL_MAX env var)""") - - @default('gateway_retry_interval_max') - def gateway_retry_interval_max_default(self): - return float(os.environ.get('JUPYTER_GATEWAY_RETRY_INTERVAL_MAX', self.gateway_retry_interval_max_default_value)) - - gateway_retry_max_default_value = 5 - gateway_retry_max_env = 'JUPYTER_GATEWAY_RETRY_MAX' - gateway_retry_max = Int(default_value=gateway_retry_max_default_value, config=True, - help="""The maximum retries allowed for HTTP reconnection with the Gateway server. - (JUPYTER_GATEWAY_RETRY_MAX env var)""") - - @default('gateway_retry_max') - def gateway_retry_max_default(self): - return int(os.environ.get('JUPYTER_GATEWAY_RETRY_MAX', self.gateway_retry_max_default_value)) - - @property - def gateway_enabled(self): - return bool(self.url is not None and len(self.url) > 0) - - # Ensure KERNEL_LAUNCH_TIMEOUT has a default value. - KERNEL_LAUNCH_TIMEOUT = int(os.environ.get('KERNEL_LAUNCH_TIMEOUT', 40)) - - def init_static_args(self): - """Initialize arguments used on every request. Since these are static values, we'll - perform this operation once. - - """ - # Ensure that request timeout and KERNEL_LAUNCH_TIMEOUT are the same, taking the - # greater value of the two. - if self.request_timeout < float(GatewayClient.KERNEL_LAUNCH_TIMEOUT): - self.request_timeout = float(GatewayClient.KERNEL_LAUNCH_TIMEOUT) - elif self.request_timeout > float(GatewayClient.KERNEL_LAUNCH_TIMEOUT): - GatewayClient.KERNEL_LAUNCH_TIMEOUT = int(self.request_timeout) - # Ensure any adjustments are reflected in env. - os.environ['KERNEL_LAUNCH_TIMEOUT'] = str(GatewayClient.KERNEL_LAUNCH_TIMEOUT) - - self._static_args['headers'] = json.loads(self.headers) - if 'Authorization' not in self._static_args['headers'].keys(): - self._static_args['headers'].update({ - 'Authorization': 'token {}'.format(self.auth_token) - }) - self._static_args['connect_timeout'] = self.connect_timeout - self._static_args['request_timeout'] = self.request_timeout - self._static_args['validate_cert'] = self.validate_cert - if self.client_cert: - self._static_args['client_cert'] = self.client_cert - self._static_args['client_key'] = self.client_key - if self.ca_certs: - self._static_args['ca_certs'] = self.ca_certs - if self.http_user: - self._static_args['auth_username'] = self.http_user - if self.http_pwd: - self._static_args['auth_password'] = self.http_pwd - - def load_connection_args(self, **kwargs): - """Merges the static args relative to the connection, with the given keyword arguments. If statics - have yet to be initialized, we'll do that here. - - """ - if len(self._static_args) == 0: - self.init_static_args() - - for arg, static_value in self._static_args.items(): - if arg == 'headers': - given_value = kwargs.setdefault(arg, {}) - if isinstance(given_value, dict): - given_value.update(static_value) - else: - kwargs[arg] = static_value - return kwargs - - -async def gateway_request(endpoint, **kwargs): - """Make an async request to kernel gateway endpoint, returns a response """ - client = AsyncHTTPClient() - kwargs = GatewayClient.instance().load_connection_args(**kwargs) - try: - response = await client.fetch(endpoint, **kwargs) - # Trap a set of common exceptions so that we can inform the user that their Gateway url is incorrect - # or the server is not running. - # NOTE: We do this here since this handler is called during the Notebook's startup and subsequent refreshes - # of the tree view. - except ConnectionRefusedError as e: - raise web.HTTPError( - 503, - "Connection refused from Gateway server url '{}'. Check to be sure the" - " Gateway instance is running.".format(GatewayClient.instance().url) - ) from e - except HTTPError as e: - # This can occur if the host is valid (e.g., foo.com) but there's nothing there. - raise web.HTTPError(e.code, "Error attempting to connect to Gateway server url '{}'. " - "Ensure gateway url is valid and the Gateway instance is running.". - format(GatewayClient.instance().url)) from e - except gaierror as e: - raise web.HTTPError( - 404, - "The Gateway server specified in the gateway_url '{}' doesn't appear to be valid. Ensure gateway " - "url is valid and the Gateway instance is running.".format(GatewayClient.instance().url) - ) from e - - return response - - -class GatewayKernelManager(AsyncMappingKernelManager): - """Kernel manager that supports remote kernels hosted by Jupyter Kernel or Enterprise Gateway.""" - - # We'll maintain our own set of kernel ids - _kernels = {} - - def __init__(self, **kwargs): - super().__init__(**kwargs) - self.base_endpoint = url_path_join(GatewayClient.instance().url, GatewayClient.instance().kernels_endpoint) - - def __contains__(self, kernel_id): - return kernel_id in self._kernels - - def remove_kernel(self, kernel_id): - """Complete override since we want to be more tolerant of missing keys """ - try: - return self._kernels.pop(kernel_id) - except KeyError: - pass - - def _get_kernel_endpoint_url(self, kernel_id=None): - """Builds a url for the kernels endpoint - - Parameters - ---------- - kernel_id: kernel UUID (optional) - """ - if kernel_id: - return url_path_join(self.base_endpoint, url_escape(str(kernel_id))) - - return self.base_endpoint - - async def start_kernel(self, kernel_id=None, path=None, **kwargs): - """Start a kernel for a session and return its kernel_id. - - Parameters - ---------- - kernel_id : uuid - The uuid to associate the new kernel with. If this - is not None, this kernel will be persistent whenever it is - requested. - path : API path - The API path (unicode, '/' delimited) for the cwd. - Will be transformed to an OS path relative to root_dir. - """ - self.log.info('Request start kernel: kernel_id=%s, path="%s"', kernel_id, path) - - if kernel_id is None: - if path is not None: - kwargs['cwd'] = self.cwd_for_path(path) - kernel_name = kwargs.get('kernel_name', 'python3') - kernel_url = self._get_kernel_endpoint_url() - self.log.debug("Request new kernel at: %s" % kernel_url) - - # Let KERNEL_USERNAME take precedent over http_user config option. - if os.environ.get('KERNEL_USERNAME') is None and GatewayClient.instance().http_user: - os.environ['KERNEL_USERNAME'] = GatewayClient.instance().http_user - - kernel_env = {k: v for (k, v) in dict(os.environ).items() if k.startswith('KERNEL_') - or k in GatewayClient.instance().env_whitelist.split(",")} - - # Convey the full path to where this notebook file is located. - if path is not None and kernel_env.get('KERNEL_WORKING_DIR') is None: - kernel_env['KERNEL_WORKING_DIR'] = kwargs['cwd'] - - json_body = json_encode({'name': kernel_name, 'env': kernel_env}) - - response = await gateway_request( - kernel_url, method='POST', headers={'Content-Type': 'application/json'}, body=json_body - ) - kernel = json_decode(response.body) - kernel_id = kernel['id'] - self.log.info("Kernel started: %s" % kernel_id) - self.log.debug("Kernel args: %r" % kwargs) - else: - kernel = await self.get_kernel(kernel_id) - kernel_id = kernel['id'] - self.log.info("Using existing kernel: %s" % kernel_id) - - self._kernels[kernel_id] = kernel - return kernel_id - - async def get_kernel(self, kernel_id=None, **kwargs): - """Get kernel for kernel_id. - - Parameters - ---------- - kernel_id : uuid - The uuid of the kernel. - """ - kernel_url = self._get_kernel_endpoint_url(kernel_id) - self.log.debug("Request kernel at: %s" % kernel_url) - try: - response = await gateway_request(kernel_url, method='GET') - except web.HTTPError as error: - if error.status_code == 404: - self.log.warn("Kernel not found at: %s" % kernel_url) - self.remove_kernel(kernel_id) - kernel = None - else: - raise - else: - kernel = json_decode(response.body) - # Only update our models if we already know about this kernel - if kernel_id in self._kernels: - self._kernels[kernel_id] = kernel - self.log.debug("Kernel retrieved: %s", kernel) - else: - self.log.warning("Kernel '%s' is not managed by this instance.", kernel_id) - kernel = None - return kernel - - async def kernel_model(self, kernel_id): - """Return a dictionary of kernel information described in the - JSON standard model. - - Parameters - ---------- - kernel_id : uuid - The uuid of the kernel. - """ - self.log.debug("RemoteKernelManager.kernel_model: %s", kernel_id) - model = await self.get_kernel(kernel_id) - return model - - async def list_kernels(self, **kwargs): - """Get a list of kernels.""" - kernel_url = self._get_kernel_endpoint_url() - self.log.debug("Request list kernels: %s", kernel_url) - response = await gateway_request(kernel_url, method='GET') - kernels = json_decode(response.body) - # Only update our models if we already know about the kernels - self._kernels = {x['id']: x for x in kernels if x['id'] in self._kernels} - return list(self._kernels.values()) - - async def shutdown_kernel(self, kernel_id, now=False, restart=False): - """Shutdown a kernel by its kernel uuid. - - Parameters - ========== - kernel_id : uuid - The id of the kernel to shutdown. - now : bool - Shutdown the kernel immediately (True) or gracefully (False) - restart : bool - The purpose of this shutdown is to restart the kernel (True) - """ - kernel_url = self._get_kernel_endpoint_url(kernel_id) - self.log.debug("Request shutdown kernel at: %s", kernel_url) - response = await gateway_request(kernel_url, method='DELETE') - self.log.debug("Shutdown kernel response: %d %s", response.code, response.reason) - self.remove_kernel(kernel_id) - - async def restart_kernel(self, kernel_id, now=False, **kwargs): - """Restart a kernel by its kernel uuid. - - Parameters - ========== - kernel_id : uuid - The id of the kernel to restart. - """ - kernel_url = self._get_kernel_endpoint_url(kernel_id) + '/restart' - self.log.debug("Request restart kernel at: %s", kernel_url) - response = await gateway_request( - kernel_url, method='POST', headers={'Content-Type': 'application/json'}, body=json_encode({}) - ) - self.log.debug("Restart kernel response: %d %s", response.code, response.reason) - - async def interrupt_kernel(self, kernel_id, **kwargs): - """Interrupt a kernel by its kernel uuid. - - Parameters - ========== - kernel_id : uuid - The id of the kernel to interrupt. - """ - kernel_url = self._get_kernel_endpoint_url(kernel_id) + '/interrupt' - self.log.debug("Request interrupt kernel at: %s", kernel_url) - response = await gateway_request( - kernel_url, method='POST', headers={'Content-Type': 'application/json'}, body=json_encode({}) - ) - self.log.debug("Interrupt kernel response: %d %s", response.code, response.reason) - - def shutdown_all(self, now=False): - """Shutdown all kernels.""" - # Note: We have to make this sync because the NotebookApp does not wait for async. - shutdown_kernels = [] - kwargs = {'method': 'DELETE'} - kwargs = GatewayClient.instance().load_connection_args(**kwargs) - client = HTTPClient() - for kernel_id in self._kernels: - kernel_url = self._get_kernel_endpoint_url(kernel_id) - self.log.debug("Request delete kernel at: %s", kernel_url) - try: - response = client.fetch(kernel_url, **kwargs) - except HTTPError: - pass - else: - self.log.debug("Delete kernel response: %d %s", response.code, response.reason) - shutdown_kernels.append(kernel_id) # avoid changing dict size during iteration - client.close() - for kernel_id in shutdown_kernels: - self.remove_kernel(kernel_id) - - -class GatewayKernelSpecManager(KernelSpecManager): - - def __init__(self, **kwargs): - super().__init__(**kwargs) - base_endpoint = url_path_join(GatewayClient.instance().url, - GatewayClient.instance().kernelspecs_endpoint) - - self.base_endpoint = GatewayKernelSpecManager._get_endpoint_for_user_filter(base_endpoint) - self.base_resource_endpoint = url_path_join(GatewayClient.instance().url, - GatewayClient.instance().kernelspecs_resource_endpoint) - - @staticmethod - def _get_endpoint_for_user_filter(default_endpoint): - kernel_user = os.environ.get('KERNEL_USERNAME') - if kernel_user: - return '?user='.join([default_endpoint, kernel_user]) - return default_endpoint - - def _get_kernelspecs_endpoint_url(self, kernel_name=None): - """Builds a url for the kernels endpoint - - Parameters - ---------- - kernel_name: kernel name (optional) - """ - if kernel_name: - return url_path_join(self.base_endpoint, url_escape(kernel_name)) - - return self.base_endpoint - - async def get_all_specs(self): - fetched_kspecs = await self.list_kernel_specs() - - # get the default kernel name and compare to that of this server. - # If different log a warning and reset the default. However, the - # caller of this method will still return this server's value until - # the next fetch of kernelspecs - at which time they'll match. - km = self.parent.kernel_manager - remote_default_kernel_name = fetched_kspecs.get('default') - if remote_default_kernel_name != km.default_kernel_name: - self.log.info("Default kernel name on Gateway server ({gateway_default}) differs from " - "Notebook server ({notebook_default}). Updating to Gateway server's value.". - format(gateway_default=remote_default_kernel_name, - notebook_default=km.default_kernel_name)) - km.default_kernel_name = remote_default_kernel_name - - remote_kspecs = fetched_kspecs.get('kernelspecs') - return remote_kspecs - - async def list_kernel_specs(self): - """Get a list of kernel specs.""" - kernel_spec_url = self._get_kernelspecs_endpoint_url() - self.log.debug("Request list kernel specs at: %s", kernel_spec_url) - response = await gateway_request(kernel_spec_url, method='GET') - kernel_specs = json_decode(response.body) - return kernel_specs - - async def get_kernel_spec(self, kernel_name, **kwargs): - """Get kernel spec for kernel_name. - - Parameters - ---------- - kernel_name : str - The name of the kernel. - """ - kernel_spec_url = self._get_kernelspecs_endpoint_url(kernel_name=str(kernel_name)) - self.log.debug("Request kernel spec at: %s" % kernel_spec_url) - try: - response = await gateway_request(kernel_spec_url, method='GET') - except web.HTTPError as error: - if error.status_code == 404: - # Convert not found to KeyError since that's what the Notebook handler expects - # message is not used, but might as well make it useful for troubleshooting - raise KeyError( - 'kernelspec {kernel_name} not found on Gateway server at: {gateway_url}'. - format(kernel_name=kernel_name, gateway_url=GatewayClient.instance().url) - ) from error - else: - raise - else: - kernel_spec = json_decode(response.body) - - return kernel_spec - - async def get_kernel_spec_resource(self, kernel_name, path): - """Get kernel spec for kernel_name. - - Parameters - ---------- - kernel_name : str - The name of the kernel. - path : str - The name of the desired resource - """ - kernel_spec_resource_url = url_path_join(self.base_resource_endpoint, str(kernel_name), str(path)) - self.log.debug("Request kernel spec resource '{}' at: {}".format(path, kernel_spec_resource_url)) - try: - response = await gateway_request(kernel_spec_resource_url, method='GET') - except web.HTTPError as error: - if error.status_code == 404: - kernel_spec_resource = None - else: - raise - else: - kernel_spec_resource = response.body - return kernel_spec_resource - - -class GatewaySessionManager(SessionManager): - kernel_manager = Instance('notebook.gateway.managers.GatewayKernelManager') - - async def kernel_culled(self, kernel_id): - """Checks if the kernel is still considered alive and returns true if its not found. """ - kernel = await self.kernel_manager.get_kernel(kernel_id) - return kernel is None diff --git a/notebook/i18n/README.md b/notebook/i18n/README.md deleted file mode 100644 index 1f0ea34a4..000000000 --- a/notebook/i18n/README.md +++ /dev/null @@ -1,134 +0,0 @@ -# Implementation Notes for Internationalization of Jupyter Notebook - -The implementation of i18n features for jupyter notebook is still a work-in-progress: - -- User interface strings are (mostly) handled -- Console messages are not handled (their usefulness in a translated environment is questionable) -- Tooling has to be refined - -However… - -## How the language is selected ? - -1. `jupyter notebook` command reads the `LANG` environment variable at startup, -(`xx_XX` or just `xx` form, where `xx` is the language code you're wanting to -run in). - -Hint: if running Windows, you can set it in PowerShell with `${Env:LANG} = "xx_XX"`. - if running Ubuntu 14, you should set environment variable `LANGUAGE="xx_XX"`. - -2. The preferred language for web pages in your browser settings (`xx`) is - also used. At the moment, it has to be first in the list. - -## Contributing and managing translations - -Finding and translating the `.pot` files could be (partially) done with a translation API, see the repo [Jupyter Notebook Azure Translator](https://github.com/berendjan/Jupyter-Notebook-Azure-Translator.git) for a possible starting point. (Not affiliated with Jupyter) - -### Requirements - -- *pybabel* (could be installed `pip install babel`) -- *po2json* (could be installed with `npm install -g po2json`) - -**All i18n-related commands are done from the related directory :** - - cd notebook/i18n/ - -### Message extraction - -The translatable material for notebook is split into 3 `.pot` files, as follows: - -- *notebook/i18n/notebook.pot* - Console and startup messages, basically anything that is - produced by Python code. -- *notebook/i18n/nbui.pot* - User interface strings, as extracted from the Jinja2 templates - in *notebook/templates/\*.html* -- *noteook/i18n/nbjs.pot* - JavaScript strings and dialogs, which contain much of the visible - user interface for Jupyter notebook. - -To extract the messages from the source code whenever new material is added, use the -`pybabel` command: - -```shell -pybabel extract -F babel_notebook.cfg -o notebook.pot --no-wrap --project Jupyter . -pybabel extract -F babel_nbui.cfg -o nbui.pot --no-wrap --project Jupyter . -pybabel extract -F babel_nbjs.cfg -o nbjs.pot --no-wrap --project Jupyter . -``` - -After this is complete you have 3 `.pot` files that you can give to a translator for your favorite language. - -Finding and translating the `.pot` files could be (partially done with a translation API, see the repo [Jupyter Notebook Azure Translator](https://github.com/berendjan/Jupyter-Notebook-Azure-Translator.git) for a possible starting point. (Not affiliated with Jupyter) - -### Messages compilation - -After the source material has been translated, you should have 3 `.po` files with the same base names -as the `.pot` files above. Put them in `notebook/i18n/${LANG}/LC_MESSAGES`, where `${LANG}` is the language -code for your desired language ( i.e. German = "de", Japanese = "ja", etc. ). - -*notebook.po* and *nbui.po* need to be converted from `.po` to `.mo` format for -use at runtime. - -```shell -pybabel compile -D notebook -f -l ${LANG} -i ${LANG}/LC_MESSAGES/notebook.po -o ${LANG}/LC_MESSAGES/notebook.mo -pybabel compile -D nbui -f -l ${LANG} -i ${LANG}/LC_MESSAGES/nbui.po -o ${LANG}/LC_MESSAGES/nbui.mo -``` - -*nbjs.po* needs to be converted to JSON for use within the JavaScript code, with *po2json*, as follows: - - po2json -p -F -f jed1.x -d nbjs ${LANG}/LC_MESSAGES/nbjs.po ${LANG}/LC_MESSAGES/nbjs.json - -When new languages get added, their language codes should be added to *notebook/i18n/nbjs.json* -under the `supported_languages` element. - -### Tips for Jupyter developers - -The biggest "mistake" I found while doing i18n enablement was the habit of constructing UI messages -from English "piece parts". For example, code like: - -```javascript -var msg = "Enter a new " + type + "name:" -``` - -where `type` is either "file", "directory", or "notebook".... - -is problematic when doing translations, because the surrounding text may need to vary -depending on the inserted word. In this case, you need to switch it and use complete phrases, -as follows: - -```javascript -var rename_msg = function (type) { - switch(type) { - case 'file': return _("Enter a new file name:"); - case 'directory': return _("Enter a new directory name:"); - case 'notebook': return _("Enter a new notebook name:"); - default: return _("Enter a new name:"); - } -} -``` - -Also you need to remember that adding an "s" or "es" to an English word to -create the plural form doesn't translate well. Some languages have as many as 5 or 6 different -plural forms for differing numbers, so using an API such as ngettext() is necessary in order -to handle these cases properly. - -### Known issues and future evolutions - -1. Right now there are two different places where the desired language is set. At startup time, the Jupyter console's messages pay attention to the setting of the `${LANG}` environment variable -as set in the shell at startup time. Unfortunately, this is also the time where the Jinja2 -environment is set up, which means that the template stuff will always come from this setting. -We really want to be paying attention to the browser's settings for the stuff that happens in the -browser, so we need to be able to retrieve this information after the browser is started and somehow -communicate this back to Jinja2. So far, I haven't yet figured out how to do this, which means that if the ${LANG} at startup doesn't match the browser's settings, you could potentially get a mix -of languages in the UI ( never a good thing ). - -2. We will need to decide if console messages should be translatable, and enable them if desired. -3. The keyboard shortcut editor was implemented after the i18n work was completed, so that portion -does not have translation support at this time. -4. Babel's documentation has instructions on how to integrate messages extraction -into your *setup.py* so that eventually we can just do: - - ./setup.py extract_messages - -I hope to get this working at some point in the near future. -5. The conversions from `.po` to `.mo` probably can and should be done using `setup.py install`. - - -Any questions or comments please let me know @JCEmmons on github (emmo@us.ibm.com) diff --git a/notebook/i18n/__init__.py b/notebook/i18n/__init__.py deleted file mode 100644 index 83f65c5fd..000000000 --- a/notebook/i18n/__init__.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Server functions for loading translations -""" -from collections import defaultdict -import errno -import io -import json -from os.path import dirname, join as pjoin -import re - -I18N_DIR = dirname(__file__) -# Cache structure: -# {'nbjs': { # Domain -# 'zh-CN': { # Language code -# : -# ... -# } -# }} -TRANSLATIONS_CACHE = {'nbjs': {}} - - -_accept_lang_re = re.compile(r''' -(?P[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?) -(\s*;\s*q\s*=\s* - (?P[01](.\d+)?) -)?''', re.VERBOSE) - -def parse_accept_lang_header(accept_lang): - """Parses the 'Accept-Language' HTTP header. - - Returns a list of language codes in *ascending* order of preference - (with the most preferred language last). - """ - by_q = defaultdict(list) - for part in accept_lang.split(','): - m = _accept_lang_re.match(part.strip()) - if not m: - continue - lang, qvalue = m.group('lang', 'qvalue') - # Browser header format is zh-CN, gettext uses zh_CN - lang = lang.replace('-', '_') - if qvalue is None: - qvalue = 1. - else: - qvalue = float(qvalue) - if qvalue == 0: - continue # 0 means not accepted - by_q[qvalue].append(lang) - if '_' in lang: - short = lang.split('_')[0] - if short != 'en': - by_q[qvalue].append(short) - - res = [] - for qvalue, langs in sorted(by_q.items()): - res.extend(sorted(langs)) - return res - -def load(language, domain='nbjs'): - """Load translations from an nbjs.json file""" - try: - f = io.open(pjoin(I18N_DIR, language, 'LC_MESSAGES', 'nbjs.json'), - encoding='utf-8') - except IOError as e: - if e.errno != errno.ENOENT: - raise - return {} - - with f: - data = json.load(f) - return data["locale_data"][domain] - -def cached_load(language, domain='nbjs'): - """Load translations for one language, using in-memory cache if available""" - domain_cache = TRANSLATIONS_CACHE[domain] - try: - return domain_cache[language] - except KeyError: - data = load(language, domain) - domain_cache[language] = data - return data - -def combine_translations(accept_language, domain='nbjs'): - """Combine translations for multiple accepted languages. - - Returns data re-packaged in jed1.x format. - """ - lang_codes = parse_accept_lang_header(accept_language) - combined = {} - for language in lang_codes: - if language == 'en': - # en is default, all translations are in frontend. - combined.clear() - else: - combined.update(cached_load(language, domain)) - - combined[''] = {"domain":"nbjs"} - - return { - "domain": domain, - "locale_data": { - domain: combined - } - } diff --git a/notebook/i18n/babel_nbjs.cfg b/notebook/i18n/babel_nbjs.cfg deleted file mode 100644 index 492f24773..000000000 --- a/notebook/i18n/babel_nbjs.cfg +++ /dev/null @@ -1,11 +0,0 @@ -[javascript: notebook/static/base/js/*.js] -extract_messages = $._, i18n.msg._ - -[javascript: notebook/static/notebook/js/*.js] -extract_messages = $._, i18n.msg._ - -[javascript: notebook/static/notebook/js/celltoolbarpresets/*.js] -extract_messages = $._, i18n.msg._ - -[javascript: notebook/static/tree/js/*.js] -extract_messages = $._, i18n.msg._ diff --git a/notebook/i18n/babel_nbui.cfg b/notebook/i18n/babel_nbui.cfg deleted file mode 100644 index 271554a8a..000000000 --- a/notebook/i18n/babel_nbui.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[jinja2: notebook/templates/**.html] - encoding = utf-8 -[extractors] - jinja2 = jinja2.ext:babel_extract diff --git a/notebook/i18n/babel_notebook.cfg b/notebook/i18n/babel_notebook.cfg deleted file mode 100644 index d4e3cf9b7..000000000 --- a/notebook/i18n/babel_notebook.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[python: notebook/*.py] -[python: notebook/services/contents/*.py] diff --git a/notebook/i18n/fr_FR/LC_MESSAGES/nbjs.po b/notebook/i18n/fr_FR/LC_MESSAGES/nbjs.po deleted file mode 100644 index a8b01bf13..000000000 --- a/notebook/i18n/fr_FR/LC_MESSAGES/nbjs.po +++ /dev/null @@ -1,2131 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2018-08-29 18:52+0200\n" -"PO-Revision-Date: 2018-10-04 00:34+0200\n" -"Last-Translator: Mathis HAMMEL \n" -"Language-Team: \n" -"Language: fr_FR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 1.8.11\n" - -#: notebook/static/base/js/dialog.js:161 -msgid "Manually edit the JSON below to manipulate the metadata for this cell." -msgstr "" -"Éditer manuellement le JSON ci-dessous pour manipuler les méta-données de " -"cette cellule" - -#: notebook/static/base/js/dialog.js:163 -msgid "" -"Manually edit the JSON below to manipulate the metadata for this notebook." -msgstr "" -"Éditer manuellement le JSON ci-dessous pour manipuler les méta-données de " -"ce notebook." - -#: notebook/static/base/js/dialog.js:165 -msgid "" -" We recommend putting custom metadata attributes in an appropriately named " -"substructure, so they don't conflict with those of others." -msgstr "" -" Il est recommandé de placer les attributs personnalisés de méta-données dans " -"une sous-structure nommée de manière appropriée, afin qu'ils n'interfèrent " -"pas avec ceux des autres." - -#: notebook/static/base/js/dialog.js:180 -msgid "Edit the metadata" -msgstr "Éditer les méta-données" - -#: notebook/static/base/js/dialog.js:202 -msgid "Edit Notebook Metadata" -msgstr "Éditer les méta-données du Notebook" - -#: notebook/static/base/js/dialog.js:204 -msgid "Edit Cell Metadata" -msgstr "Éditer les méta-données de la cellule" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/notebook.js:475 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:859 -#: notebook/static/tree/js/notebooklist.js:1418 -msgid "Cancel" -msgstr "Annuler" - -#: notebook/static/base/js/dialog.js:208 -msgid "Edit" -msgstr "Éditer" - -# OK -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/kernelselector.js:278 -#: notebook/static/notebook/js/mathjaxutils.js:42 -#: notebook/static/notebook/js/notebook.js:469 -#: notebook/static/notebook/js/notificationarea.js:187 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/newnotebook.js:97 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "OK" -msgstr "OK" - -#: notebook/static/base/js/dialog.js:208 -msgid "Apply" -msgstr "Appliquer" - -#: notebook/static/base/js/dialog.js:225 -msgid "WARNING: Could not save invalid JSON." -msgstr "ATTENTION: Impossible de sauvegarder du JSON invalide." - -#: notebook/static/base/js/dialog.js:247 -msgid "There are no attachments for this cell." -msgstr "Il n'y a pas de pièce-jointe à cette cellule." - -#: notebook/static/base/js/dialog.js:250 -msgid "Current cell attachments" -msgstr "Pièce-jointes actuelles de la cellule" - -#: notebook/static/base/js/dialog.js:259 -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:46 -msgid "Attachments" -msgstr "Pièces jointes" - -#: notebook/static/base/js/dialog.js:283 -msgid "Restore" -msgstr "Restaurer" - -#: notebook/static/base/js/dialog.js:293 -#: notebook/static/tree/js/notebooklist.js:1018 -msgid "Delete" -msgstr "Supprimer" - -#: notebook/static/base/js/dialog.js:342 notebook/static/base/js/dialog.js:386 -msgid "Edit attachments" -msgstr "Modifier les pièces jointes" - -#: notebook/static/base/js/dialog.js:348 -msgid "Edit Notebook Attachments" -msgstr "Modifier les pièces jointes du Notebook" - -#: notebook/static/base/js/dialog.js:350 -msgid "Edit Cell Attachments" -msgstr "Modifier les pièces jointes de la cellule" - -#: notebook/static/base/js/dialog.js:373 -msgid "Select a file to insert." -msgstr "Sélectionner un fichier à insérer." - -#: notebook/static/base/js/dialog.js:399 -msgid "Select a file" -msgstr "Sélectionner un fichier" - -#: notebook/static/notebook/js/about.js:14 -msgid "You are using Jupyter notebook." -msgstr "Vous utilisez un notebook Jupyter." - -#: notebook/static/notebook/js/about.js:16 -msgid "The version of the notebook server is: " -msgstr "La version du serveur de notebook est : " - -#: notebook/static/notebook/js/about.js:22 -msgid "The server is running on this version of Python:" -msgstr "Le serveur utilise la version de Python :" - -#: notebook/static/notebook/js/about.js:25 -msgid "Waiting for kernel to be available..." -msgstr "En attente de disponibilité du noyau..." - -#: notebook/static/notebook/js/about.js:27 -msgid "Server Information:" -msgstr "Information du serveur :" - -#: notebook/static/notebook/js/about.js:29 -msgid "Current Kernel Information:" -msgstr "Information du Noyau courant :" - -#: notebook/static/notebook/js/about.js:32 -msgid "Could not access sys_info variable for version information." -msgstr "" -"Impossible d'accéder à la variable sys_info pour l'information relative aux " -"versions." - -#: notebook/static/notebook/js/about.js:34 -msgid "Cannot find sys_info!" -msgstr "Impossible de trouver sys_info !" - -#: notebook/static/notebook/js/about.js:38 -msgid "About Jupyter Notebook" -msgstr "À propos de Jupyter Notebook" - -#: notebook/static/notebook/js/about.js:47 -msgid "unable to contact kernel" -msgstr "impossible de joindre le noyau" - -#: notebook/static/notebook/js/actions.js:69 -msgid "toggle rtl layout" -msgstr "Changer le sens d'organisation de l'interface" - -#: notebook/static/notebook/js/actions.js:70 -msgid "" -"Toggle the screen directionality between left-to-right and right-to-left" -msgstr "" -"Changer le sens d'organisation des éléments d'interface entre gauche-à-" -"droite et droite-à-gauche" - -#: notebook/static/notebook/js/actions.js:76 -msgid "edit command mode keyboard shortcuts" -msgstr "modifier les raccourcis clavier du mode commande" - -#: notebook/static/notebook/js/actions.js:77 -msgid "Open a dialog to edit the command mode keyboard shortcuts" -msgstr "Ouvrir un dialogue pour éditer les racourcis clavier du mode commande" - -#: notebook/static/notebook/js/actions.js:97 -msgid "restart kernel" -msgstr "redémarrer le noyau" - -#: notebook/static/notebook/js/actions.js:98 -msgid "restart the kernel (no confirmation dialog)" -msgstr "redémarrer le noyau (sans confirmation)" - -#: notebook/static/notebook/js/actions.js:106 -msgid "confirm restart kernel" -msgstr "confirmer le redémarrage du noyau" - -#: notebook/static/notebook/js/actions.js:107 -msgid "restart the kernel (with dialog)" -msgstr "redémarrer le noyau (avec confirmation)" - -#: notebook/static/notebook/js/actions.js:113 -msgid "restart kernel and run all cells" -msgstr "redémarrer le noyau et exécuter toutes les cellules" - -#: notebook/static/notebook/js/actions.js:114 -msgid "" -"restart the kernel, then re-run the whole notebook (no confirmation dialog)" -msgstr "" -"redémarrer le noyau, et ré-exécuter tout le notebook (sans confirmation)" - -#: notebook/static/notebook/js/actions.js:120 -msgid "confirm restart kernel and run all cells" -msgstr "confirmer le redémarrage du noyau et l'exécution des cellules" - -#: notebook/static/notebook/js/actions.js:121 -msgid "restart the kernel, then re-run the whole notebook (with dialog)" -msgstr "" -"redémarrer le noyau, et ré-exécuter tout le notebook (sans confirmation)" - -#: notebook/static/notebook/js/actions.js:127 -msgid "restart kernel and clear output" -msgstr "redémarrer le noyau, et effacer les sorties" - -#: notebook/static/notebook/js/actions.js:128 -msgid "restart the kernel and clear all output (no confirmation dialog)" -msgstr "redémarrer le noyau et effacer les sorties (sans confirmation)" - -#: notebook/static/notebook/js/actions.js:134 -msgid "confirm restart kernel and clear output" -msgstr "confirmer le redémarrage du noyau et l'effacement des sorties" - -#: notebook/static/notebook/js/actions.js:135 -msgid "restart the kernel and clear all output (with dialog)" -msgstr "redémarrer le noyau et effacer les sorties (avec confirmation)" - -#: notebook/static/notebook/js/actions.js:142 -#: notebook/static/notebook/js/actions.js:143 -msgid "interrupt the kernel" -msgstr "interrompre le noyau" - -#: notebook/static/notebook/js/actions.js:150 -msgid "run cell and select next" -msgstr "exécuter la cellule et sélectionner la suivante" - -#: notebook/static/notebook/js/actions.js:152 -msgid "run cell, select below" -msgstr "exécuter la cellule, sélectionner la suivante" - -#: notebook/static/notebook/js/actions.js:159 -#: notebook/static/notebook/js/actions.js:160 -msgid "run selected cells" -msgstr "exécuter les cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:167 -#: notebook/static/notebook/js/actions.js:168 -msgid "run cell and insert below" -msgstr "exécuter la cellule et insérer après" - -#: notebook/static/notebook/js/actions.js:175 -#: notebook/static/notebook/js/actions.js:176 -msgid "run all cells" -msgstr "exécuter toutes les cellules" - -#: notebook/static/notebook/js/actions.js:183 -#: notebook/static/notebook/js/actions.js:184 -msgid "run all cells above" -msgstr "exécuter toutes les cellules précédentes" - -#: notebook/static/notebook/js/actions.js:190 -#: notebook/static/notebook/js/actions.js:191 -msgid "run all cells below" -msgstr "Exécuter toutes les cellules suivantes" - -#: notebook/static/notebook/js/actions.js:197 -#: notebook/static/notebook/js/actions.js:198 -msgid "enter command mode" -msgstr "ouvrir le mode commande" - -#: notebook/static/notebook/js/actions.js:205 -#: notebook/static/notebook/js/actions.js:206 -msgid "insert image" -msgstr "insérer une image" - -#: notebook/static/notebook/js/actions.js:213 -#: notebook/static/notebook/js/actions.js:214 -msgid "cut cell attachments" -msgstr "couper les pièces-jointes de la cellule" - -#: notebook/static/notebook/js/actions.js:221 -#: notebook/static/notebook/js/actions.js:222 -msgid "copy cell attachments" -msgstr "copier les pièces-jointes de la cellule" - -#: notebook/static/notebook/js/actions.js:229 -#: notebook/static/notebook/js/actions.js:230 -msgid "paste cell attachments" -msgstr "coller les pièces-jointes de la cellule" - -#: notebook/static/notebook/js/actions.js:237 -#: notebook/static/notebook/js/actions.js:238 -msgid "split cell at cursor" -msgstr "séparer la cellule au niveau du curseur" - -#: notebook/static/notebook/js/actions.js:245 -#: notebook/static/notebook/js/actions.js:246 -msgid "enter edit mode" -msgstr "activer le mode d'édition" - -#: notebook/static/notebook/js/actions.js:253 -msgid "select previous cell" -msgstr "sélectionner la cellule précédente" - -#: notebook/static/notebook/js/actions.js:254 -msgid "select cell above" -msgstr "sélectionner la cellule précédente" - -#: notebook/static/notebook/js/actions.js:265 -msgid "select next cell" -msgstr "sélectionner la cellule suivante" - -#: notebook/static/notebook/js/actions.js:266 -msgid "select cell below" -msgstr "sélectionner la cellule suivante" - -#: notebook/static/notebook/js/actions.js:277 -msgid "extend selection above" -msgstr "étendre la sélection vers le haut" - -#: notebook/static/notebook/js/actions.js:278 -msgid "extend selected cells above" -msgstr "étendre les cellules sélectionnées vers le haut" - -#: notebook/static/notebook/js/actions.js:289 -msgid "extend selection below" -msgstr "étendre la sélection vers le bas" - -#: notebook/static/notebook/js/actions.js:290 -msgid "extend selected cells below" -msgstr "étendre les cellules sélectionnées vers le bas" - -#: notebook/static/notebook/js/actions.js:301 -#: notebook/static/notebook/js/actions.js:302 -msgid "cut selected cells" -msgstr "couper les cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:312 -#: notebook/static/notebook/js/actions.js:313 -msgid "copy selected cells" -msgstr "copier les cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:327 -#: notebook/static/notebook/js/actions.js:328 -msgid "paste cells above" -msgstr "coller les cellules avant" - -#: notebook/static/notebook/js/actions.js:335 -#: notebook/static/notebook/js/actions.js:336 -msgid "paste cells below" -msgstr "coller les cellules après" - -#: notebook/static/notebook/js/actions.js:344 -#: notebook/static/notebook/js/actions.js:345 -msgid "insert cell above" -msgstr "insérer une cellule avant" - -#: notebook/static/notebook/js/actions.js:354 -#: notebook/static/notebook/js/actions.js:355 -msgid "insert cell below" -msgstr "insérer une cellule après" - -#: notebook/static/notebook/js/actions.js:365 -#: notebook/static/notebook/js/actions.js:366 -msgid "change cell to code" -msgstr "transformer en cellule de code" - -#: notebook/static/notebook/js/actions.js:373 -#: notebook/static/notebook/js/actions.js:374 -msgid "change cell to markdown" -msgstr "transformer celllule en markdown" - -#: notebook/static/notebook/js/actions.js:381 -#: notebook/static/notebook/js/actions.js:382 -msgid "change cell to raw" -msgstr "transformer en texte brut (pour NBConvert)" - -#: notebook/static/notebook/js/actions.js:389 -#: notebook/static/notebook/js/actions.js:390 -msgid "change cell to heading 1" -msgstr "transformer en titre de niveau 1" - -#: notebook/static/notebook/js/actions.js:397 -#: notebook/static/notebook/js/actions.js:398 -msgid "change cell to heading 2" -msgstr "transformer en titre de niveau 2" - -#: notebook/static/notebook/js/actions.js:405 -#: notebook/static/notebook/js/actions.js:406 -msgid "change cell to heading 3" -msgstr "transformer en titre de niveau 3" - -#: notebook/static/notebook/js/actions.js:413 -#: notebook/static/notebook/js/actions.js:414 -msgid "change cell to heading 4" -msgstr "transformer en titre de niveau 4" - -#: notebook/static/notebook/js/actions.js:421 -#: notebook/static/notebook/js/actions.js:422 -msgid "change cell to heading 5" -msgstr "transformer en titre de niveau 5" - -#: notebook/static/notebook/js/actions.js:429 -#: notebook/static/notebook/js/actions.js:430 -msgid "change cell to heading 6" -msgstr "transformer en titre de niveau 6" - -#: notebook/static/notebook/js/actions.js:437 -msgid "toggle cell output" -msgstr "afficher/masquer la sortie de cellule" - -#: notebook/static/notebook/js/actions.js:438 -msgid "toggle output of selected cells" -msgstr "afficher/masquer la sortie des cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:445 -msgid "toggle cell scrolling" -msgstr "afficher/masquer la barre de défilement de la sortie de la cellule" - -#: notebook/static/notebook/js/actions.js:446 -msgid "toggle output scrolling of selected cells" -msgstr "" -"afficher/masquer la barre de défilement des la sortie des cellules " -"sélectionnées" - -#: notebook/static/notebook/js/actions.js:453 -msgid "clear cell output" -msgstr "effacer la sortie de la cellule" - -#: notebook/static/notebook/js/actions.js:454 -msgid "clear output of selected cells" -msgstr "effacer la sortie des cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:460 -msgid "move cells down" -msgstr "déplacer les cellules vers le bas" - -#: notebook/static/notebook/js/actions.js:461 -msgid "move selected cells down" -msgstr "déplacer les cellules sélectionnées vers le bas" - -#: notebook/static/notebook/js/actions.js:469 -msgid "move cells up" -msgstr "déplacer les cellules vers le haut" - -#: notebook/static/notebook/js/actions.js:470 -msgid "move selected cells up" -msgstr "déplacer les cellules sélectionnées vers le haut" - -#: notebook/static/notebook/js/actions.js:478 -#: notebook/static/notebook/js/actions.js:479 -msgid "toggle line numbers" -msgstr "afficher/masquer les numéros de ligne" - -#: notebook/static/notebook/js/actions.js:486 -#: notebook/static/notebook/js/actions.js:487 -msgid "show keyboard shortcuts" -msgstr "afficher les raccourcis clavier" - -#: notebook/static/notebook/js/actions.js:494 -msgid "delete cells" -msgstr "supprimer les cellules" - -#: notebook/static/notebook/js/actions.js:495 -msgid "delete selected cells" -msgstr "supprimer les cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:502 -#: notebook/static/notebook/js/actions.js:503 -msgid "undo cell deletion" -msgstr "annuler la suppression de cellule" - -#: notebook/static/notebook/js/actions.js:512 -msgid "merge cell with previous cell" -msgstr "fusionner la cellule avec la précédente" - -#: notebook/static/notebook/js/actions.js:513 -msgid "merge cell above" -msgstr "fusionner la cellule avec les précédentes" - -#: notebook/static/notebook/js/actions.js:519 -msgid "merge cell with next cell" -msgstr "fusionner la cellule avec la suivante" - -#: notebook/static/notebook/js/actions.js:520 -msgid "merge cell below" -msgstr "fusionner la cellule avec les suivantes" - -#: notebook/static/notebook/js/actions.js:527 -#: notebook/static/notebook/js/actions.js:528 -msgid "merge selected cells" -msgstr "fusionnnner les cellules sélectionnées" - -#: notebook/static/notebook/js/actions.js:535 -msgid "merge cells" -msgstr "fusionnnner les cellules" - -#: notebook/static/notebook/js/actions.js:536 -msgid "" -"merge selected cells, or current cell with cell below if only one cell is " -"selected" -msgstr "" -"fusionner les cellules sélectionnées, ou la cellule courante avec la " -"suivante si une unique cellule est sélectionnée" - -#: notebook/static/notebook/js/actions.js:549 -msgid "show command pallette" -msgstr "afficher la palette de commandes" - -#: notebook/static/notebook/js/actions.js:550 -msgid "open the command palette" -msgstr "ouvrir la palette de commandes" - -#: notebook/static/notebook/js/actions.js:557 -msgid "toggle all line numbers" -msgstr "afficher/masquer tous les numéros de ligne" - -#: notebook/static/notebook/js/actions.js:558 -msgid "toggles line numbers in all cells, and persist the setting" -msgstr "afficher/masquer les numéros de ligne dans toutes ces cellules, et s'en souvenir dans les paramètres" - -#: notebook/static/notebook/js/actions.js:569 -msgid "show all line numbers" -msgstr "afficher/masquer tous les numéros de ligne" - -#: notebook/static/notebook/js/actions.js:570 -msgid "show line numbers in all cells, and persist the setting" -msgstr "" -"afficher les numéros de ligne dans toutes les cellules, et s'en souvenir dans les paramètres" - -#: notebook/static/notebook/js/actions.js:579 -msgid "hide all line numbers" -msgstr "masquer tous les numéros de ligne" - -#: notebook/static/notebook/js/actions.js:580 -msgid "hide line numbers in all cells, and persist the setting" -msgstr "masquer les numéros de ligne dans toutes les cellules, et s'en souvenir dans les paramètres" - -#: notebook/static/notebook/js/actions.js:589 -msgid "toggle header" -msgstr "afficher/masquer l'en-tête" - -#: notebook/static/notebook/js/actions.js:590 -msgid "switch between showing and hiding the header" -msgstr "afficher/masquer l'en-tête" - -#: notebook/static/notebook/js/actions.js:605 -#: notebook/static/notebook/js/actions.js:606 -msgid "show the header" -msgstr "afficher l'en-tête" - -#: notebook/static/notebook/js/actions.js:615 -#: notebook/static/notebook/js/actions.js:616 -msgid "hide the header" -msgstr "masquer l'en-tête" - -#: notebook/static/notebook/js/actions.js:646 -msgid "toggle toolbar" -msgstr "afficher/masquer la barre d'outils" - -#: notebook/static/notebook/js/actions.js:647 -msgid "switch between showing and hiding the toolbar" -msgstr "afficher/masquer la barre d'outils" - -#: notebook/static/notebook/js/actions.js:660 -#: notebook/static/notebook/js/actions.js:661 -msgid "show the toolbar" -msgstr "afficher la barre d'outils" - -#: notebook/static/notebook/js/actions.js:669 -#: notebook/static/notebook/js/actions.js:670 -msgid "hide the toolbar" -msgstr "masquer la barre d'outils" - -#: notebook/static/notebook/js/actions.js:678 -#: notebook/static/notebook/js/actions.js:679 -msgid "close the pager" -msgstr "fermer le paginateur" - -#: notebook/static/notebook/js/actions.js:704 -msgid "ignore" -msgstr "ignorer" - -#: notebook/static/notebook/js/actions.js:710 -#: notebook/static/notebook/js/actions.js:711 -msgid "move cursor up" -msgstr "déplacer le curseur vers le haut" - -#: notebook/static/notebook/js/actions.js:731 -#: notebook/static/notebook/js/actions.js:732 -msgid "move cursor down" -msgstr "déplacer le curseur vers le bas" - -#: notebook/static/notebook/js/actions.js:750 -#: notebook/static/notebook/js/actions.js:751 -msgid "scroll notebook down" -msgstr "faire défiler le notebook vers le bas" - -#: notebook/static/notebook/js/actions.js:760 -#: notebook/static/notebook/js/actions.js:761 -msgid "scroll notebook up" -msgstr "faire défiler le notebook vers le haut" - -#: notebook/static/notebook/js/actions.js:770 -msgid "scroll cell center" -msgstr "faire défiler la cellule courante au centre" - -#: notebook/static/notebook/js/actions.js:771 -msgid "Scroll the current cell to the center" -msgstr "Faire défiler la cellule courante au centre" - -#: notebook/static/notebook/js/actions.js:781 -msgid "scroll cell top" -msgstr "faire défiler la cellule en haut" - -#: notebook/static/notebook/js/actions.js:782 -msgid "Scroll the current cell to the top" -msgstr "Faire défiler la cellule courante en haut" - -#: notebook/static/notebook/js/actions.js:792 -msgid "duplicate notebook" -msgstr "dupliquer le notebook" - -#: notebook/static/notebook/js/actions.js:793 -msgid "Create and open a copy of the current notebook" -msgstr "Créer et ouvrir une copie du notebook courant" - -#: notebook/static/notebook/js/actions.js:799 -msgid "trust notebook" -msgstr "faire confiance à ce notebook" - -#: notebook/static/notebook/js/actions.js:800 -msgid "Trust the current notebook" -msgstr "Faire confiance au notebook courant" - -#: notebook/static/notebook/js/actions.js:806 -msgid "rename notebook" -msgstr "renommer le notebook" - -#: notebook/static/notebook/js/actions.js:807 -msgid "Rename the current notebook" -msgstr "Renommer le notebook courant" - -#: notebook/static/notebook/js/actions.js:813 -msgid "toggle all cells output collapsed" -msgstr "afficher/masquer toutes les sorties en mode compact" - -#: notebook/static/notebook/js/actions.js:814 -msgid "Toggle the hidden state of all output areas" -msgstr "Afficher/masquer toutes les sorties" - -#: notebook/static/notebook/js/actions.js:820 -msgid "toggle all cells output scrolled" -msgstr "afficher/masquer toutes les sorties en mode défilement" - -#: notebook/static/notebook/js/actions.js:821 -msgid "Toggle the scrolling state of all output areas" -msgstr "Activer/désactiver le défilement de toutes les sorties" - -#: notebook/static/notebook/js/actions.js:828 -msgid "clear all cells output" -msgstr "effacer le contenu de toutes les sorties de cellules" - -#: notebook/static/notebook/js/actions.js:829 -msgid "Clear the content of all the outputs" -msgstr "Effacer le contenu de toutes les sorties" - -#: notebook/static/notebook/js/actions.js:835 -msgid "save notebook" -msgstr "enregistrer le notebook" - -#: notebook/static/notebook/js/actions.js:836 -msgid "Save and Checkpoint" -msgstr "Créer une nouvelle sauvegarde" - -#: notebook/static/notebook/js/cell.js:79 -msgid "Warning: accessing Cell.cm_config directly is deprecated." -msgstr "Attention : accéder à Cell.cm_config directement est déprécié." - -#: notebook/static/notebook/js/cell.js:763 -#, python-format -msgid "Unrecognized cell type: %s" -msgstr "Type de cellule non reconnu : %s" - -#: notebook/static/notebook/js/cell.js:777 -msgid "Unrecognized cell type" -msgstr "Type de cellule non reconnu" - -#: notebook/static/notebook/js/celltoolbar.js:296 -#, python-format -msgid "Error in cell toolbar callback %s" -msgstr "Erreur dans le callback %s de la barre d'outil de cellule" - -#: notebook/static/notebook/js/clipboard.js:53 -#, python-format -msgid "Clipboard types: %s" -msgstr "Types de données dans le presse-papier : %s" - -#: notebook/static/notebook/js/clipboard.js:96 -msgid "Dialog for paste from system clipboard" -msgstr "Boîte de dialogue pour coller depuis le presse-papier du système" - -#: notebook/static/notebook/js/clipboard.js:109 -msgid "Ctrl-V" -msgstr "Ctrl-V" - -#: notebook/static/notebook/js/clipboard.js:111 -msgid "Cmd-V" -msgstr "Cmd-V" - -#: notebook/static/notebook/js/clipboard.js:113 -#, python-format -msgid "Press %s again to paste" -msgstr "Appuyer sur %s à nouveau pour coller" - -#: notebook/static/notebook/js/clipboard.js:116 -msgid "Why is this needed? " -msgstr "Pourquoi ce comportement ?" - -#: notebook/static/notebook/js/clipboard.js:118 -msgid "We can't get paste events in this browser without a text box. " -msgstr "" -"Il n'est pas possible de capturer les évènements « coller » dans le " -"navigateur sans champ de texte" - -#: notebook/static/notebook/js/clipboard.js:119 -msgid "There's an invisible text box focused in this dialog." -msgstr "Cette boîte de dialogue contient un champ de texte invisible." - -#: notebook/static/notebook/js/clipboard.js:125 -#, python-format -msgid "%s to paste" -msgstr "%s pour coller" - -#: notebook/static/notebook/js/codecell.js:310 -msgid "Can't execute cell since kernel is not set." -msgstr "Impossible d'exécuter cette cellule car aucun noyau n'est choisi." - -#: notebook/static/notebook/js/codecell.js:472 -msgid "In" -msgstr "Entrée" - -#: notebook/static/notebook/js/kernelselector.js:269 -#, python-format -msgid "Could not find a kernel matching %s. Please select a kernel:" -msgstr "" -"Impossible de trouver un noyau correspondant à %s. Merci de sélectionner un " -"noyau :" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Continue Without Kernel" -msgstr "Poursuivre sans noyau" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Set Kernel" -msgstr "Choisir le noyau" - -#: notebook/static/notebook/js/kernelselector.js:281 -msgid "Kernel not found" -msgstr "Noyau introuvable" - -#: notebook/static/notebook/js/kernelselector.js:319 -#: notebook/static/tree/js/newnotebook.js:99 -msgid "Creating Notebook Failed" -msgstr "La création du notebook a échoué" - -#: notebook/static/notebook/js/kernelselector.js:320 -#: notebook/static/tree/js/notebooklist.js:1360 -#, python-format -msgid "The error was: %s" -msgstr "L'erreur est : %s" - -#: notebook/static/notebook/js/maintoolbar.js:54 -msgid "Run" -msgstr "Exécuter" - -#: notebook/static/notebook/js/maintoolbar.js:76 -msgid "Code" -msgstr "Code" - -#: notebook/static/notebook/js/maintoolbar.js:77 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/static/notebook/js/maintoolbar.js:78 -msgid "Raw NBConvert" -msgstr "Texte Brut (pour NBConvert)" - -#: notebook/static/notebook/js/maintoolbar.js:79 -msgid "Heading" -msgstr "Titre" - -#: notebook/static/notebook/js/maintoolbar.js:115 -msgid "unrecognized cell type:" -msgstr "type de cellule non reconnu :" - -#: notebook/static/notebook/js/mathjaxutils.js:45 -#, python-format -msgid "Failed to retrieve MathJax from '%s'" -msgstr "Impossible de récupérer MathJax depuis '%s'" - -#: notebook/static/notebook/js/mathjaxutils.js:47 -msgid "Math/LaTeX rendering will be disabled." -msgstr "Le rendu Math/LaTex sera désactivé." - -#: notebook/static/notebook/js/menubar.js:220 -msgid "Trusted Notebook" -msgstr "Notebook de confiance" - -#: notebook/static/notebook/js/menubar.js:226 -msgid "Trust Notebook" -msgstr "Faire confiance à ce Notebook" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16 -#: notebook/static/notebook/js/menubar.js:383 -msgid "None" -msgstr "Aucun(e)" - -#: notebook/static/notebook/js/menubar.js:406 -msgid "No checkpoints" -msgstr "Pas de point de sauvegarde" - -#: notebook/static/notebook/js/menubar.js:465 -msgid "Opens in a new window" -msgstr "Ouvrir dans une nouvelle fenêtre" - -#: notebook/static/notebook/js/notebook.js:431 -msgid "Autosave in progress, latest changes may be lost." -msgstr "" -"Auto-sauvegarde en cours, les dernières modifications pourraient être " -"perdues." - -#: notebook/static/notebook/js/notebook.js:433 -msgid "Unsaved changes will be lost." -msgstr "Les modifications non sauvegardées seront perdues." - -#: notebook/static/notebook/js/notebook.js:438 -msgid "The Kernel is busy, outputs may be lost." -msgstr "Le noyau est occupé, les sorties pourraient être perdues." - -#: notebook/static/notebook/js/notebook.js:461 -msgid "This notebook is version %1$s, but we only fully support up to %2$s." -msgstr "" -"Ce notebook est prévu pour la version %1$s du logiciel, mais nous supportons " -"au maximum la version %2$s." - -#: notebook/static/notebook/js/notebook.js:463 -msgid "" -"You can still work with this notebook, but cell and output types introduced " -"in later notebook versions will not be available." -msgstr "" -"Vous pouvez continuer à travailler avec ce notebook, mais les types de " -"cellules et de sorties introduits dans les versions ultérieures du logiciel " -"ne seront pas disponibles." - -#: notebook/static/notebook/js/notebook.js:470 -msgid "Restart and Run All Cells" -msgstr "Relancer et exécuter toutes les cellules" - -#: notebook/static/notebook/js/notebook.js:471 -msgid "Restart and Clear All Outputs" -msgstr "Relancer et effacer toutes les sorties" - -#: notebook/static/notebook/js/notebook.js:472 -msgid "Restart" -msgstr "Relancer" - -#: notebook/static/notebook/js/notebook.js:473 -msgid "Continue Running" -msgstr "Poursuivre l'exécution" - -#: notebook/static/notebook/js/notebook.js:474 -msgid "Reload" -msgstr "Recharger" - -#: notebook/static/notebook/js/notebook.js:476 -msgid "Overwrite" -msgstr "Écraser" - -#: notebook/static/notebook/js/notebook.js:477 -msgid "Trust" -msgstr "Faire confiance" - -#: notebook/static/notebook/js/notebook.js:478 -msgid "Revert" -msgstr "Rétablir" - -#: notebook/static/notebook/js/notebook.js:483 -msgid "Newer Notebook" -msgstr "Notebook plus récent" - -#: notebook/static/notebook/js/notebook.js:1548 -msgid "Use markdown headings" -msgstr "Utiliser les titres markdown" - -#: notebook/static/notebook/js/notebook.js:1550 -msgid "" -"Jupyter no longer uses special heading cells. Instead, write your headings " -"in Markdown cells using # characters:" -msgstr "" -"Jupyter n'utilise plus de cellules spéciales pour les titres. À la place, " -"utiliser la syntaxe de titre dans des cellules Markdown avec les caractères " -"# :" - -#: notebook/static/notebook/js/notebook.js:1553 -msgid "## This is a level 2 heading" -msgstr "## Ceci est un titre de niveau 2" - -#: notebook/static/notebook/js/notebook.js:2248 -msgid "Restart kernel and re-run the whole notebook?" -msgstr "Redémarrer le noyau et ré-exécuter l'ensemble du noteboook ?" - -#: notebook/static/notebook/js/notebook.js:2250 -msgid "" -"Are you sure you want to restart the current kernel and re-execute the whole " -"notebook? All variables and outputs will be lost." -msgstr "" -"Êtes-vous certain de vouloir redémarrer le noyau actuel et ré-exécuter " -"l'ensemble du notebook ? Toutes les variables et sorties seront perdues." - -#: notebook/static/notebook/js/notebook.js:2275 -msgid "Restart kernel and clear all output?" -msgstr "Redémarrer le noyau et effacer toutes les sorties ?" - -#: notebook/static/notebook/js/notebook.js:2277 -msgid "" -"Do you want to restart the current kernel and clear all output? All " -"variables and outputs will be lost." -msgstr "" -"Souhaitez-vous redémarrer le noyau actuel et effacer toutes les sorties ? " -"Toutes les variables et les sorties seront perdues." - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Restart kernel?" -msgstr "Redémarrer le noyau ?" - -#: notebook/static/notebook/js/notebook.js:2324 -msgid "Do you want to restart the current kernel? All variables will be lost." -msgstr "" -"Souhaitez-vous redémarrer le noyau actuel ? " -"Toutes les variables seront perdues." - -#: notebook/static/notebook/js/notebook.js:2320 -msgid "Shutdown kernel?" -msgstr "Arrêter le noyau ?" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "" -"Do you want to shutdown the current kernel? All variables will be lost." -msgstr "" -"Souhaitez-vous redémarrer le noyau actuel ? " -"Toutes les variables seront perdues." - -#: notebook/static/notebook/js/notebook.js:2734 -msgid "Notebook changed" -msgstr "Notebook modifié" - -#: notebook/static/notebook/js/notebook.js:2735 -msgid "" -"The notebook file has changed on disk since the last time we opened or saved " -"it. Do you want to overwrite the file on disk with the version open here, or " -"load the version on disk (reload the page) ?" -msgstr "" -"Le fichier du notebook a changé sur le disque depuis que vous l'avez ouvert " -"ou sauvegardé. Souhaitez-vous écraser le fichier sur le disque avec la " -"version ouverte ici ou charger la version présente sur le disque (recharge " -"la page) ?" - -#: notebook/static/notebook/js/notebook.js:2782 -#: notebook/static/notebook/js/notebook.js:2990 -msgid "Notebook validation failed" -msgstr "La validation du notebook a échoué" - -#: notebook/static/notebook/js/notebook.js:2785 -msgid "" -"The save operation succeeded, but the notebook does not appear to be valid. " -"The validation error was:" -msgstr "" -"La sauvegarde a réussi, mais le notebook semble invalide. L'erreur de " -"validation est :" - -#: notebook/static/notebook/js/notebook.js:2836 -msgid "" -"A trusted Jupyter notebook may execute hidden malicious code when you open " -"it. Selecting trust will immediately reload this notebook in a trusted " -"state. For more information, see the Jupyter security documentation: " -msgstr "" -"Un notebook Jupyter auquel vous faites confiance peut exécuter du code " -"malicieux quand vous l'ouvrez. Choisir de faire confiance à ce notebook va " -"le recharger immédiatement en mode confiance. Pour davantage d'information, " -"voir la section sécurité dans la documentation de Jupyter." - -#: notebook/static/notebook/js/notebook.js:2840 -msgid "here" -msgstr "ici" - -#: notebook/static/notebook/js/notebook.js:2848 -msgid "Trust this notebook?" -msgstr "Faire confiance à ce notebook ?" - -#: notebook/static/notebook/js/notebook.js:2981 -msgid "Notebook failed to load" -msgstr "Le chargement du notebook a échoué" - -#: notebook/static/notebook/js/notebook.js:2983 -msgid "The error was: " -msgstr "L'erreur est : " - -#: notebook/static/notebook/js/notebook.js:2987 -msgid "See the error console for details." -msgstr "Voir la console d'erreur pour davantage de détails." - -#: notebook/static/notebook/js/notebook.js:2995 -msgid "The notebook also failed validation:" -msgstr "La validation du notebook a échoué :" - -#: notebook/static/notebook/js/notebook.js:2997 -msgid "" -"An invalid notebook may not function properly. The validation error was:" -msgstr "" -"Un notebook non valide peut dysfonctionner. L'erreur de validation est :" - -#: notebook/static/notebook/js/notebook.js:3036 -#, python-format -msgid "" -"This notebook has been converted from an older notebook format to the " -"current notebook format v(%s)." -msgstr "" -"Ce notebook a été converti depuis un format plus ancien de notebook vers le " -"format actuel v(%s)." - -#: notebook/static/notebook/js/notebook.js:3038 -#, python-format -msgid "" -"This notebook has been converted from a newer notebook format to the current " -"notebook format v(%s)." -msgstr "" -"Ce notebook a été converti depuis un format plus récent de notebook vers le " -"format actuel v(%s)." - -#: notebook/static/notebook/js/notebook.js:3046 -msgid "" -"The next time you save this notebook, the current notebook format will be " -"used." -msgstr "" -"Au prochain enregistrement de ce notebook, le format actuel de notebook " -"sera utilisé" - -#: notebook/static/notebook/js/notebook.js:3051 -msgid "Older versions of Jupyter may not be able to read the new format." -msgstr "" -"D'anciennes version de Jupyter peuvent ne pas être en mesure de lire le " -"nouveau format." - -#: notebook/static/notebook/js/notebook.js:3053 -msgid "Some features of the original notebook may not be available." -msgstr "" -"Certaines fonctionalités du notebook d'origine peuvent ne pas être " -"disponibles." - -#: notebook/static/notebook/js/notebook.js:3056 -msgid "To preserve the original version, close the notebook without saving it." -msgstr "" -"Pour préserver la version originale, fermer le notebook sans l'enregistrer." - -#: notebook/static/notebook/js/notebook.js:3061 -msgid "Notebook converted" -msgstr "Notebook converti" - -#: notebook/static/notebook/js/notebook.js:3083 -msgid "(No name)" -msgstr "(Sans nom)" - -#: notebook/static/notebook/js/notebook.js:3131 -#, python-format -msgid "" -"An unknown error occurred while loading this notebook. This version can load " -"notebook formats %s or earlier. See the server log for details." -msgstr "" -"Une erreur inconnue s'est produite pendant le chargement de ce notebook. " -"Cette version peut charger des formats de notebooks %s ou plus ancien. Voir " -"les journaux du serveur pour davantage d'information." - -#: notebook/static/notebook/js/notebook.js:3142 -msgid "Error loading notebook" -msgstr "Erreur pendant le chargement du notebook" - -#: notebook/static/notebook/js/notebook.js:3243 -msgid "Are you sure you want to revert the notebook to the latest checkpoint?" -msgstr "Êtes-vous certain de vouloir restaurer la dernière sauvegarde ?" - -#: notebook/static/notebook/js/notebook.js:3246 -msgid "This cannot be undone." -msgstr "Impossible d'annuler." - -#: notebook/static/notebook/js/notebook.js:3249 -msgid "The checkpoint was last updated at:" -msgstr "Dernière sauvegarde à : " - -#: notebook/static/notebook/js/notebook.js:3260 -msgid "Revert notebook to checkpoint" -msgstr "Restaurer le notebook à une sauvegarde antérieure" - -#: notebook/static/notebook/js/notificationarea.js:77 -#: notebook/static/notebook/js/tour.js:61 -#: notebook/static/notebook/js/tour.js:67 -msgid "Edit Mode" -msgstr "Mode Édition" - -#: notebook/static/notebook/js/notificationarea.js:84 -#: notebook/static/notebook/js/notificationarea.js:88 -#: notebook/static/notebook/js/tour.js:54 -msgid "Command Mode" -msgstr "Mode Commande" - -#: notebook/static/notebook/js/notificationarea.js:95 -msgid "Kernel Created" -msgstr "Noyau créé" - -#: notebook/static/notebook/js/notificationarea.js:99 -msgid "Connecting to kernel" -msgstr "Connexion au noyau" - -#: notebook/static/notebook/js/notificationarea.js:103 -msgid "Not Connected" -msgstr "Non connecté" - -#: notebook/static/notebook/js/notificationarea.js:106 -msgid "click to reconnect" -msgstr "cliquer pour reconnecter" - -#: notebook/static/notebook/js/notificationarea.js:115 -msgid "Restarting kernel" -msgstr "Noyau en cours de redémarrage" - -#: notebook/static/notebook/js/notificationarea.js:129 -msgid "Kernel Restarting" -msgstr "Noyau en cours de redémarrage" - -#: notebook/static/notebook/js/notificationarea.js:130 -msgid "The kernel appears to have died. It will restart automatically." -msgstr "Le noyau semble planté. Il va redémarrer automatiquement." - -#: notebook/static/notebook/js/notificationarea.js:140 -#: notebook/static/notebook/js/notificationarea.js:198 -#: notebook/static/notebook/js/notificationarea.js:218 -msgid "Dead kernel" -msgstr "Noyau planté" - -#: notebook/static/notebook/js/notificationarea.js:141 -#: notebook/static/notebook/js/notificationarea.js:219 -#: notebook/static/notebook/js/notificationarea.js:266 -msgid "Kernel Dead" -msgstr "Noyau planté" - -#: notebook/static/notebook/js/notificationarea.js:145 -msgid "Interrupting kernel" -msgstr "Noyau en cours d'interruption" - -#: notebook/static/notebook/js/notificationarea.js:151 -msgid "No Connection to Kernel" -msgstr "Pas de connexion au noyau" - -#: notebook/static/notebook/js/notificationarea.js:161 -msgid "" -"A connection to the notebook server could not be established. The notebook " -"will continue trying to reconnect. Check your network connection or notebook " -"server configuration." -msgstr "" -"La connexion au serveur de notebook ne peut pas être établie. Le notebook va " -"continuer ses tentatives. Vérifiez votre connexion réseau ou les paramètres " -"du serveur de notebook." - -#: notebook/static/notebook/js/notificationarea.js:166 -msgid "Connection failed" -msgstr "Échec de la connexion" - -#: notebook/static/notebook/js/notificationarea.js:179 -msgid "No kernel" -msgstr "Pas de noyau" - -#: notebook/static/notebook/js/notificationarea.js:180 -msgid "Kernel is not running" -msgstr "Le noyau n'est pas actif" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Don't Restart" -msgstr "Ne pas redémarrer" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Try Restarting Now" -msgstr "Essayer de redémarrer maintenant" - -#: notebook/static/notebook/js/notificationarea.js:191 -msgid "" -"The kernel has died, and the automatic restart has failed. It is possible " -"the kernel cannot be restarted. If you are not able to restart the kernel, " -"you will still be able to save the notebook, but running code will no longer " -"work until the notebook is reopened." -msgstr "" -"Le noyau a planté, et le redémarrage automatique a échoué. Il est possible " -"que le noyau ne puisse pas être relancé. Si c'est le cas, vous pourrez " -"toujours sauvegarder le notebook, mais l'exécution de code ne fonctionnera " -"pas jusqu'à la ré-ouverture du notebook." - -#: notebook/static/notebook/js/notificationarea.js:225 -msgid "No Kernel" -msgstr "Pas de Noyau" - -#: notebook/static/notebook/js/notificationarea.js:252 -msgid "Failed to start the kernel" -msgstr "Échec du démarrage du noyau" - -#: notebook/static/notebook/js/notificationarea.js:272 -#: notebook/static/notebook/js/notificationarea.js:292 -#: notebook/static/notebook/js/notificationarea.js:306 -msgid "Kernel Busy" -msgstr "Noyau occupé" - -#: notebook/static/notebook/js/notificationarea.js:273 -msgid "Kernel starting, please wait..." -msgstr "Noyau en cours de démarrage, patientez…" - -#: notebook/static/notebook/js/notificationarea.js:279 -#: notebook/static/notebook/js/notificationarea.js:286 -msgid "Kernel Idle" -msgstr "Noyau inactif" - -#: notebook/static/notebook/js/notificationarea.js:280 -msgid "Kernel ready" -msgstr "Noyau prêt" - -#: notebook/static/notebook/js/notificationarea.js:297 -msgid "Using kernel: " -msgstr "Noyau utilisé : " - -#: notebook/static/notebook/js/notificationarea.js:298 -msgid "Only candidate for language: %1$s was %2$s." -msgstr "Unique candidat pour le langage : %1$s était %2$s." - -#: notebook/static/notebook/js/notificationarea.js:319 -msgid "Loading notebook" -msgstr "Chargement du notebook en cours" - -#: notebook/static/notebook/js/notificationarea.js:322 -msgid "Notebook loaded" -msgstr "Notebook chargé" - -#: notebook/static/notebook/js/notificationarea.js:325 -msgid "Saving notebook" -msgstr "Enregistrement du notebook en cours" - -#: notebook/static/notebook/js/notificationarea.js:328 -msgid "Notebook saved" -msgstr "Notebook enregistré" - -#: notebook/static/notebook/js/notificationarea.js:331 -msgid "Notebook save failed" -msgstr "L'enregistrement du notebook a échoué" - -#: notebook/static/notebook/js/notificationarea.js:334 -msgid "Notebook copy failed" -msgstr "La copie du notebook a échoué" - -#: notebook/static/notebook/js/notificationarea.js:339 -msgid "Checkpoint created" -msgstr "Sauvegarde créée" - -#: notebook/static/notebook/js/notificationarea.js:347 -msgid "Checkpoint failed" -msgstr "Échec de la sauvegarde" - -#: notebook/static/notebook/js/notificationarea.js:350 -msgid "Checkpoint deleted" -msgstr "Sauvegarde supprimée" - -#: notebook/static/notebook/js/notificationarea.js:353 -msgid "Checkpoint delete failed" -msgstr "Échec de la suppression de la sauvegarde" - -#: notebook/static/notebook/js/notificationarea.js:356 -msgid "Restoring to checkpoint..." -msgstr "Restauration de la sauvegarde..." - -#: notebook/static/notebook/js/notificationarea.js:359 -msgid "Checkpoint restore failed" -msgstr "La restauration de la sauvegarde a échoué" - -#: notebook/static/notebook/js/notificationarea.js:364 -msgid "Autosave disabled" -msgstr "Sauvegarde automatique désactivée" - -#: notebook/static/notebook/js/notificationarea.js:367 -#, python-format -msgid "Saving every %d sec." -msgstr "Sauvegarde toutes les %d sec." - -#: notebook/static/notebook/js/notificationarea.js:383 -msgid "Trusted" -msgstr "Fiable" - -#: notebook/static/notebook/js/notificationarea.js:385 -msgid "Not Trusted" -msgstr "Non fiable" - -#: notebook/static/notebook/js/outputarea.js:75 -msgid "click to expand output" -msgstr "cliquer pour afficher toute la sortie" - -#: notebook/static/notebook/js/outputarea.js:79 -msgid "click to expand output; double click to hide output" -msgstr "" -"cliquer pour afficher toute la sortie ; double-cliquer pour masquer la sortie" - -#: notebook/static/notebook/js/outputarea.js:167 -msgid "click to unscroll output; double click to hide" -msgstr "" -"cliquer pour faire défiler la sortie vers le haut ; double-cliquer pour " -"masquer" - -#: notebook/static/notebook/js/outputarea.js:174 -msgid "click to scroll output; double click to hide" -msgstr "cliquer pour faire défiler la sortie ; double-cliquer pour masquer" - -#: notebook/static/notebook/js/outputarea.js:422 -msgid "Javascript error adding output!" -msgstr "Erreur JavaScript pendant l'écriture de la sortie !" - -#: notebook/static/notebook/js/outputarea.js:427 -msgid "See your browser Javascript console for more details." -msgstr "" -"Voir la console JavaScript de votre navigateur pour plus d'informations." - -#: notebook/static/notebook/js/outputarea.js:468 -#, python-format -msgid "Out[%d]:" -msgstr "Sortie[%d] :" - -#: notebook/static/notebook/js/outputarea.js:577 -#, python-format -msgid "Unrecognized output: %s" -msgstr "Sortie non reconnue : %s" - -#: notebook/static/notebook/js/pager.js:36 -msgid "Open the pager in an external window" -msgstr "Ouvrir le paginateur dans une fenêtre externe" - -#: notebook/static/notebook/js/pager.js:45 -msgid "Close the pager" -msgstr "Fermer le paginateur" - -#: notebook/static/notebook/js/pager.js:148 -msgid "Jupyter Pager" -msgstr "Paginateur de Jupyter" - -#: notebook/static/notebook/js/quickhelp.js:39 -#: notebook/static/notebook/js/quickhelp.js:49 -#: notebook/static/notebook/js/quickhelp.js:50 -msgid "go to cell start" -msgstr "aller au début de la cellule" - -#: notebook/static/notebook/js/quickhelp.js:40 -#: notebook/static/notebook/js/quickhelp.js:51 -#: notebook/static/notebook/js/quickhelp.js:52 -msgid "go to cell end" -msgstr "aller à la fin de la cellule" - -#: notebook/static/notebook/js/quickhelp.js:41 -#: notebook/static/notebook/js/quickhelp.js:53 -msgid "go one word left" -msgstr "se déplacer d'un mot vers la gauche" - -#: notebook/static/notebook/js/quickhelp.js:42 -#: notebook/static/notebook/js/quickhelp.js:54 -msgid "go one word right" -msgstr "Se déplacer d'un mot vers la droite" - -#: notebook/static/notebook/js/quickhelp.js:43 -#: notebook/static/notebook/js/quickhelp.js:55 -msgid "delete word before" -msgstr "supprimer le mot précédent" - -#: notebook/static/notebook/js/quickhelp.js:44 -#: notebook/static/notebook/js/quickhelp.js:56 -msgid "delete word after" -msgstr "supprimer le mot suivant" - -#: notebook/static/notebook/js/quickhelp.js:61 -msgid "code completion or indent" -msgstr "complétion de code ou indentation" - -#: notebook/static/notebook/js/quickhelp.js:62 -msgid "tooltip" -msgstr "info-bulle" - -#: notebook/static/notebook/js/quickhelp.js:63 -msgid "indent" -msgstr "indenter" - -#: notebook/static/notebook/js/quickhelp.js:64 -msgid "dedent" -msgstr "dé-indenter" - -#: notebook/static/notebook/js/quickhelp.js:65 -msgid "select all" -msgstr "tout sélectionner" - -#: notebook/static/notebook/js/quickhelp.js:66 -msgid "undo" -msgstr "annuler" - -#: notebook/static/notebook/js/quickhelp.js:67 -#: notebook/static/notebook/js/quickhelp.js:68 -msgid "redo" -msgstr "refaire" - -#: notebook/static/notebook/js/quickhelp.js:102 -#: notebook/static/notebook/js/quickhelp.js:243 -msgid "Shift" -msgstr "Maj" - -#: notebook/static/notebook/js/quickhelp.js:103 -msgid "Alt" -msgstr "Alt" - -#: notebook/static/notebook/js/quickhelp.js:104 -msgid "Up" -msgstr "Haut" - -#: notebook/static/notebook/js/quickhelp.js:105 -msgid "Down" -msgstr "Bas" - -#: notebook/static/notebook/js/quickhelp.js:106 -msgid "Left" -msgstr "Gauche" - -#: notebook/static/notebook/js/quickhelp.js:107 -msgid "Right" -msgstr "Droite" - -#: notebook/static/notebook/js/quickhelp.js:108 -#: notebook/static/notebook/js/quickhelp.js:246 -msgid "Tab" -msgstr "Tab" - -#: notebook/static/notebook/js/quickhelp.js:109 -msgid "Caps Lock" -msgstr "Verr. Maj." - -#: notebook/static/notebook/js/quickhelp.js:110 -#: notebook/static/notebook/js/quickhelp.js:269 -msgid "Esc" -msgstr "Esc" - -#: notebook/static/notebook/js/quickhelp.js:111 -msgid "Ctrl" -msgstr "Ctrl" - -#: notebook/static/notebook/js/quickhelp.js:112 -#: notebook/static/notebook/js/quickhelp.js:290 -msgid "Enter" -msgstr "Entrée" - -#: notebook/static/notebook/js/quickhelp.js:113 -msgid "Page Up" -msgstr "Page Préc." - -#: notebook/static/notebook/js/quickhelp.js:114 -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "Page Down" -msgstr "Page Suiv." - -#: notebook/static/notebook/js/quickhelp.js:115 -msgid "Home" -msgstr "Accueil" - -#: notebook/static/notebook/js/quickhelp.js:116 -msgid "End" -msgstr "Fin" - -#: notebook/static/notebook/js/quickhelp.js:117 -#: notebook/static/notebook/js/quickhelp.js:245 -msgid "Space" -msgstr "Espace" - -#: notebook/static/notebook/js/quickhelp.js:118 -msgid "Backspace" -msgstr "Retour arrière" - -#: notebook/static/notebook/js/quickhelp.js:119 -msgid "Minus" -msgstr "Moins" - -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "PageUp" -msgstr "PagePréc." - -#: notebook/static/notebook/js/quickhelp.js:197 -msgid "The Jupyter Notebook has two different keyboard input modes." -msgstr "Le Notebook Jupyter offre deux modes de saisie claivier." - -#: notebook/static/notebook/js/quickhelp.js:199 -msgid "" -"Edit mode allows you to type code or text into a cell and is " -"indicated by a green cell border." -msgstr "" -"Mode Édition permet de saisir du code ou du texte dans une cellule et " -"se reconnaît à la bordure verte de la cellule." - -#: notebook/static/notebook/js/quickhelp.js:201 -msgid "" -"Command mode binds the keyboard to notebook level commands and is " -"indicated by a grey cell border with a blue left margin." -msgstr "" -"Mode Commande déclenche au clavier des actions au niveau du notebook " -"et se reconnaît à la bordure grise de la cellule, avec une marge bleue sur " -"la droite." - -#: notebook/static/notebook/js/quickhelp.js:222 -#: notebook/static/notebook/js/tooltip.js:58 -#: notebook/static/notebook/js/tooltip.js:69 -msgid "Close" -msgstr "Fermer" - -#: notebook/static/notebook/js/quickhelp.js:225 -msgid "Keyboard shortcuts" -msgstr "Raccourcis clavier" - -#: notebook/static/notebook/js/quickhelp.js:240 -msgid "Command" -msgstr "Commande" - -#: notebook/static/notebook/js/quickhelp.js:241 -msgid "Control" -msgstr "Contrôles" - -#: notebook/static/notebook/js/quickhelp.js:242 -msgid "Option" -msgstr "Option" - -#: notebook/static/notebook/js/quickhelp.js:244 -msgid "Return" -msgstr "Retour" - -#: notebook/static/notebook/js/quickhelp.js:270 -#, python-format -msgid "Command Mode (press %s to enable)" -msgstr "Mode Commande (presser %s pour l'activer)" - -#: notebook/static/notebook/js/quickhelp.js:272 -msgid "Edit Shortcuts" -msgstr "Modifier les Raccourcis Clavier" - -#: notebook/static/notebook/js/quickhelp.js:275 -msgid "edit command-mode keyboard shortcuts" -msgstr "modifier les raccourcis clavier du mode commande" - -#: notebook/static/notebook/js/quickhelp.js:292 -#, python-format -msgid "Edit Mode (press %s to enable)" -msgstr "Mode Édition (presser %s pour l'activer)" - -#: notebook/static/notebook/js/savewidget.js:49 -msgid "Autosave Failed!" -msgstr "Échec de la sauvegarde automatique !" - -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:846 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Rename" -msgstr "Renommer" - -#: notebook/static/notebook/js/savewidget.js:78 -#: notebook/static/tree/js/notebooklist.js:837 -msgid "Enter a new notebook name:" -msgstr "Saisir le nouveau nom du notebook" - -#: notebook/static/notebook/js/savewidget.js:86 -msgid "Rename Notebook" -msgstr "Renommer le Notebook" - -#: notebook/static/notebook/js/savewidget.js:98 -msgid "" -"Invalid notebook name. Notebook names must have 1 or more characters and can " -"contain any characters except :/\\. Please enter a new notebook name:" -msgstr "" -"Nom de notebook invalide. Les noms de notebooks doivent posséder au moins un " -"caractère et peuvent contenir tous les caractères sauf « /\\ ». Merci de " -"saisir un nouveau nom de notebook :" - -#: notebook/static/notebook/js/savewidget.js:103 -msgid "Renaming..." -msgstr "Renommage en cours..." - -#: notebook/static/notebook/js/savewidget.js:109 -msgid "Unknown error" -msgstr "Erreur inconnue" - -#: notebook/static/notebook/js/savewidget.js:178 -msgid "no checkpoint" -msgstr "aucune sauvegarde" - -#: notebook/static/notebook/js/savewidget.js:193 -#, python-format -msgid "Last Checkpoint: %s" -msgstr "Dernière Sauvegarde : %s" - -#: notebook/static/notebook/js/savewidget.js:217 -msgid "(unsaved changes)" -msgstr "(modifié)" - -#: notebook/static/notebook/js/savewidget.js:219 -msgid "(autosaved)" -msgstr "(auto-sauvegardé)" - -#: notebook/static/notebook/js/searchandreplace.js:74 -#, python-format -msgid "" -"Warning: too many matches (%d). Some changes might not be shown or applied." -msgstr "" -"Attention : trop de correspondances (%d). Certains changements peuvent ne " -"pas être affichés ou appliqués." - -#: notebook/static/notebook/js/searchandreplace.js:77 -#, python-format -msgid "%d match" -msgid_plural "%d matches" -msgstr[0] "%d correspondance" -msgstr[1] "%d correspondances" - -#: notebook/static/notebook/js/searchandreplace.js:145 -msgid "More than 100 matches, aborting" -msgstr "Plus de 100 correspondances, annulation" - -#: notebook/static/notebook/js/searchandreplace.js:166 -msgid "Use regex (JavaScript regex syntax)" -msgstr "Utiliser des regex (syntaxe des regex JavaScript)" - -#: notebook/static/notebook/js/searchandreplace.js:174 -msgid "Replace in selected cells" -msgstr "Remplacer dans les cellules sélectionnées" - -#: notebook/static/notebook/js/searchandreplace.js:181 -msgid "Match case" -msgstr "Sensible à la casse" - -#: notebook/static/notebook/js/searchandreplace.js:187 -msgid "Find" -msgstr "Rechercher" - -#: notebook/static/notebook/js/searchandreplace.js:203 -msgid "Replace" -msgstr "Remplacer" - -#: notebook/static/notebook/js/searchandreplace.js:255 -msgid "No matches, invalid or empty regular expression" -msgstr "" -"Aucune correspondance trouvée, expression régulière vide ou invalide." - -#: notebook/static/notebook/js/searchandreplace.js:370 -msgid "Replace All" -msgstr "Tout Remplacer" - -#: notebook/static/notebook/js/searchandreplace.js:374 -msgid "Find and Replace" -msgstr "Rechercher et Remplacer" - -#: notebook/static/notebook/js/searchandreplace.js:400 -#: notebook/static/notebook/js/searchandreplace.js:401 -msgid "find and replace" -msgstr "rechercher et remplacer" - -#: notebook/static/notebook/js/textcell.js:551 -msgid "" -"Write raw LaTeX or other formats here, for use with nbconvert. It will not " -"be rendered in the notebook. When passing through nbconvert, a Raw Cell's " -"content is added to the output unmodified." -msgstr "" -"Écrivez ici du code Latex brut ou d'autres formats, pour usage avec " -"nbconvert. Il ne sera pas rendu dans le notebook. En utilisant nbconvert, le " -"contenu d'une cellule brute est ajouté tel-quel à la sortie." - -#: notebook/static/notebook/js/tooltip.js:41 -msgid "Grow the tooltip vertically (press shift-tab twice)" -msgstr "Agrandir l'info-bulle verticallement (presser Maj-Tab deux fois)" - -#: notebook/static/notebook/js/tooltip.js:48 -msgid "show the current docstring in pager (press shift-tab 4 times)" -msgstr "" -"montrer la chaîne de documentation courante dans le paginateur (presser " -"shift-tab 4 fois)" - -#: notebook/static/notebook/js/tooltip.js:49 -msgid "Open in Pager" -msgstr "Ouvrir dans le Paginateur" - -#: notebook/static/notebook/js/tooltip.js:68 -msgid "Tooltip will linger for 10 seconds while you type" -msgstr "L'info-bulle restera affichée 10 secondes pendant votre saisie" - -#: notebook/static/notebook/js/tour.js:27 -msgid "Welcome to the Notebook Tour" -msgstr "Bienvenue dans la visite du Notebook" - -#: notebook/static/notebook/js/tour.js:30 -msgid "You can use the left and right arrow keys to go backwards and forwards." -msgstr "" -"Vous pouvez utiliser les touches gauche et droite pour continuer ou revenir " -"en arrière." - -#: notebook/static/notebook/js/tour.js:33 -msgid "Filename" -msgstr "Nom du fichier" - -#: notebook/static/notebook/js/tour.js:35 -msgid "Click here to change the filename for this notebook." -msgstr "Cliquer ici pour changer le nom du fichier de ce notebook." - -#: notebook/static/notebook/js/tour.js:39 -msgid "Notebook Menubar" -msgstr "Barre de Menu du Notebook" - -#: notebook/static/notebook/js/tour.js:40 -msgid "" -"The menubar has menus for actions on the notebook, its cells, and the kernel " -"it communicates with." -msgstr "" -"La barre de menu a des menus pour les actions concernant le notebook, ses " -"cellules, et le noyau avec lequel il communique." - -#: notebook/static/notebook/js/tour.js:44 -msgid "Notebook Toolbar" -msgstr "Barre d'outils du Notebook" - -#: notebook/static/notebook/js/tour.js:45 -msgid "" -"The toolbar has buttons for the most common actions. Hover your mouse over " -"each button for more information." -msgstr "" -"La barre d'outils a des boutons pour les actions les plus fréquentes. " -"Survoler les boutons à la souris pour plus d'information." - -#: notebook/static/notebook/js/tour.js:48 -msgid "Mode Indicator" -msgstr "Indicateur de mode" - -#: notebook/static/notebook/js/tour.js:50 -msgid "" -"The Notebook has two modes: Edit Mode and Command Mode. In this area, an " -"indicator can appear to tell you which mode you are in." -msgstr "" -"Le Notebook offre deux modes : Édition et Commande. Dans cette zone, un " -"indicateur peut vous indiquer dans quel mode vous êtes." - -#: notebook/static/notebook/js/tour.js:58 -msgid "" -"Right now you are in Command Mode, and many keyboard shortcuts are " -"available. In this mode, no icon is displayed in the indicator area." -msgstr "" -"Actuellement, vous êtes en mode Commande, et de nombreux raccourcis clavier " -"sont disponibles. Dans ce mode, aucune icône n'est affichée dans la zone " -"d'indication." - -#: notebook/static/notebook/js/tour.js:64 -msgid "" -"Pressing Enter or clicking in the input text area of the cell " -"switches to Edit Mode." -msgstr "" -"Presser Entrée ou cliquer dans la zone de saisie de la cellule " -"bascule vers le Mode Édition." - -#: notebook/static/notebook/js/tour.js:70 -msgid "" -"Notice that the border around the currently active cell changed color. " -"Typing will insert text into the currently active cell." -msgstr "" -"Notez que la bordure autour de la cellule active a changé de couleur. Saisir " -"du texte au clavier l'insérera dans la cellule active." - -#: notebook/static/notebook/js/tour.js:73 -msgid "Back to Command Mode" -msgstr "Retourner au Mode Commande" - -#: notebook/static/notebook/js/tour.js:76 -msgid "" -"Pressing Esc or clicking outside of the input text area takes " -"you back to Command Mode." -msgstr "" -"Presser Esc ou cliquer en dehors de la zone de saisie de la " -"cellule vous ramène au Mode Commande." - -#: notebook/static/notebook/js/tour.js:79 -msgid "Keyboard Shortcuts" -msgstr "Raccourcis Clavier" - -#: notebook/static/notebook/js/tour.js:91 -msgid "You can click here to get a list of all of the keyboard shortcuts." -msgstr "" -"Vous pouvez cliquer ici pour afficher une liste de tous les raccourcis " -"clavier." - -#: notebook/static/notebook/js/tour.js:94 -#: notebook/static/notebook/js/tour.js:100 -msgid "Kernel Indicator" -msgstr "Indicateur de Noyau" - -#: notebook/static/notebook/js/tour.js:97 -msgid "" -"This is the Kernel indicator. It looks like this when the Kernel is idle." -msgstr "" -"Ceci est l'indicateur de Noyau. Il a cet aspect quand le Noyau est inactif." - -#: notebook/static/notebook/js/tour.js:103 -msgid "The Kernel indicator looks like this when the Kernel is busy." -msgstr "L'indicateur de Noyau a cet aspect quand le Noyau est actif." - -#: notebook/static/notebook/js/tour.js:107 -msgid "Interrupting the Kernel" -msgstr "Interrompre le Noyau" - -#: notebook/static/notebook/js/tour.js:109 -msgid "To cancel a computation in progress, you can click here." -msgstr "Pour annuler une exécution en cours, vous pouvez cliquer ici." - -#: notebook/static/notebook/js/tour.js:114 -msgid "Notification Area" -msgstr "Zone de notification" - -#: notebook/static/notebook/js/tour.js:115 -msgid "" -"Messages in response to user actions (Save, Interrupt, etc.) appear here." -msgstr "" -"Les messages en retour d'actions utilisateur (Enregistrement, Interruption, " -"etc.) s'affichent ici." - -#: notebook/static/notebook/js/tour.js:117 -msgid "End of Tour" -msgstr "Fin de la visite" - -#: notebook/static/notebook/js/tour.js:120 -msgid "This concludes the Jupyter Notebook User Interface Tour." -msgstr "" -"C'est la fin de cette visite guidée de l'Interface utilisateur du Notebook " -"Jupyter." - -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32 -msgid "Edit Attachments" -msgstr "Modifier les Pièces-Jointes" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:19 -msgid "Cell" -msgstr "Cellule" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:29 -#: notebook/static/notebook/js/celltoolbarpresets/default.js:47 -msgid "Edit Metadata" -msgstr "Éditer les Méta-Données" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22 -msgid "Custom" -msgstr "Personnalisé" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32 -msgid "Set the MIME type of the raw cell:" -msgstr "Définir le type MIME de la cellule en texte brut :" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40 -msgid "Raw Cell MIME Type" -msgstr "Type MIME de la Cellule en Texte Brut" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74 -msgid "Raw NBConvert Format" -msgstr "Format du Texte Brut" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81 -msgid "Raw Cell Format" -msgstr "Format de la Cellule Texte Brut" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15 -msgid "Slide" -msgstr "Diapo" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:16 -msgid "Sub-Slide" -msgstr "Sous-Diapo" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:17 -msgid "Fragment" -msgstr "Extrait" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:18 -msgid "Skip" -msgstr "Sauter" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:19 -msgid "Notes" -msgstr "Notes" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35 -msgid "Slide Type" -msgstr "Type de diapo" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41 -msgid "Slideshow" -msgstr "Diaporama" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:133 -msgid "Add tag" -msgstr "Ajouter un mot-clé" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163 -msgid "" -"Edit the list of tags below. All whitespace is treated as tag separators." -msgstr "" -"Modifier la liste de mots-clés ci-dessous. Les espaces sont considérés comme " -"des séparateurs." - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172 -msgid "Edit the tags" -msgstr "Modifier les mots-clés" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186 -msgid "Edit Tags" -msgstr "Modifier Mots-Clés" - -#: notebook/static/tree/js/kernellist.js:86 -#: notebook/static/tree/js/terminallist.js:105 -msgid "Shutdown" -msgstr "Arrêter" - -#: notebook/static/tree/js/newnotebook.js:70 -#, python-format -msgid "Create a new notebook with %s" -msgstr "Créer un nouveau notebook avec %s" - -#: notebook/static/tree/js/newnotebook.js:101 -msgid "An error occurred while creating a new notebook." -msgstr "Une erreur s'est produite à la création du notebook" - -#: notebook/static/tree/js/notebooklist.js:122 -msgid "Creating File Failed" -msgstr "La création du fichier a échoué" - -#: notebook/static/tree/js/notebooklist.js:124 -msgid "An error occurred while creating a new file." -msgstr "Une erreur est survenue à la création du nouveau fichier." - -#: notebook/static/tree/js/notebooklist.js:142 -msgid "Creating Folder Failed" -msgstr "La création du répertoire a échoué" - -#: notebook/static/tree/js/notebooklist.js:144 -msgid "An error occurred while creating a new folder." -msgstr "Une erreur est survenue à la création du nouveau répertoire." - -#: notebook/static/tree/js/notebooklist.js:271 -msgid "Failed to read file" -msgstr "Échec de lecture du fichier" - -#: notebook/static/tree/js/notebooklist.js:272 -#, python-format -msgid "Failed to read file %s" -msgstr "Échec de lecture du fichier %s" - -#: notebook/static/tree/js/notebooklist.js:283 -#, python-format -msgid "The file size is %d MB. Do you still want to upload it?" -msgstr "Le fichier pèse %d MB. Êtes-vous certain de vouloir le téléverser ?" - -#: notebook/static/tree/js/notebooklist.js:286 -msgid "Large file size warning" -msgstr "Avertissement de taille de fichier élevée" - -#: notebook/static/tree/js/notebooklist.js:355 -msgid "Server error: " -msgstr "Erreur serveur :" - -#: notebook/static/tree/js/notebooklist.js:390 -msgid "The notebook list is empty." -msgstr "La liste des notebooks est vide." - -#: notebook/static/tree/js/notebooklist.js:463 -msgid "Click here to rename, delete, etc." -msgstr "Cliquer ici pour renommer, supprimer, etc." - -#: notebook/static/tree/js/notebooklist.js:503 -msgid "Running" -msgstr "Actif" - -#: notebook/static/tree/js/notebooklist.js:835 -msgid "Enter a new file name:" -msgstr "Saisir le nom du nouveau fichier :" - -#: notebook/static/tree/js/notebooklist.js:836 -msgid "Enter a new directory name:" -msgstr "Saisir le nom du nouveau répertoire :" - -#: notebook/static/tree/js/notebooklist.js:838 -msgid "Enter a new name:" -msgstr "Saisir un nouveau nom :" - -#: notebook/static/tree/js/notebooklist.js:843 -msgid "Rename file" -msgstr "Renommer le fichier" - -#: notebook/static/tree/js/notebooklist.js:844 -msgid "Rename directory" -msgstr "Renommer le répertoire" - -#: notebook/static/tree/js/notebooklist.js:845 -msgid "Rename notebook" -msgstr "Renommer le notebook" - -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Move" -msgstr "Déplacer" - -#: notebook/static/tree/js/notebooklist.js:875 -msgid "An error occurred while renaming \"%1$s\" to \"%2$s\"." -msgstr "" -"Une erreur s'est produite pendant le renommage de « %1$s » vers « %2$s »." - -#: notebook/static/tree/js/notebooklist.js:878 -msgid "Rename Failed" -msgstr "Échec du Renommage" - -#: notebook/static/tree/js/notebooklist.js:927 -#, python-format -msgid "Enter a new destination directory path for this item:" -msgid_plural "Enter a new destination directory path for these %d items:" -msgstr[0] "Saisir un nouveau chemin de destination pour cet élément :" -msgstr[1] "Saisir un nouveau chemin de destination pour ces %d éléments :" - -#: notebook/static/tree/js/notebooklist.js:940 -#, python-format -msgid "Move an Item" -msgid_plural "Move %d Items" -msgstr[0] "Déplacer un élément" -msgstr[1] "Déplacer %d éléments" - -#: notebook/static/tree/js/notebooklist.js:959 -msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"." -msgstr "" -"Une erreur s'est produite lors du déplacement de « %1$s » de « %2$s » vers " -"« %3$s »." - -#: notebook/static/tree/js/notebooklist.js:961 -msgid "Move Failed" -msgstr "Échec du déplacement" - -#: notebook/static/tree/js/notebooklist.js:1007 -#, python-format -msgid "Are you sure you want to permanently delete: \"%s\"?" -msgid_plural "" -"Are you sure you want to permanently delete the %d files or folders selected?" -msgstr[0] "Êtes-vous certain de vouloir supprimer définitivement « %s  » ?" -msgstr[1] "" -"Êtes-vous certain de vouloir supprimer définitivement les « %d  » fichiers " -"ou répertoires sélectionnés ?" - -#: notebook/static/tree/js/notebooklist.js:1035 -#, python-format -msgid "An error occurred while deleting \"%s\"." -msgstr "Une erreur s'est produite pendant la suppression de « %s »." - -#: notebook/static/tree/js/notebooklist.js:1037 -msgid "Delete Failed" -msgstr "Échec de la suppression" - -#: notebook/static/tree/js/notebooklist.js:1078 -#, python-format -msgid "Are you sure you want to duplicate: \"%s\"?" -msgid_plural "Are you sure you want to duplicate the %d files selected?" -msgstr[0] "Êtes-vous certain de vouloir dupliquer « %s » ?" -msgstr[1] "" -"Êtes-vous certain de vouloir dupliquer les « %d » fichiers sélectionnés ?" - -#: notebook/static/tree/js/notebooklist.js:1088 -msgid "Duplicate" -msgstr "Dupliquer" - -#: notebook/static/tree/js/notebooklist.js:1102 -#, python-format -msgid "An error occurred while duplicating \"%s\"." -msgstr "Une erreur s'est produite pendant la duplication de « %s »." - -#: notebook/static/tree/js/notebooklist.js:1104 -msgid "Duplicate Failed" -msgstr "Échec de la duplication" - -#: notebook/static/tree/js/notebooklist.js:1323 -msgid "Upload" -msgstr "Téléverser" - -#: notebook/static/tree/js/notebooklist.js:1332 -msgid "Invalid file name" -msgstr "Nom de fichier invalide" - -#: notebook/static/tree/js/notebooklist.js:1333 -msgid "File names must be at least one character and not start with a period" -msgstr "" -"Les noms des fichier doivent compter au moins un caractère et ne doivent pas " -"commencer avec un point." - -#: notebook/static/tree/js/notebooklist.js:1362 -msgid "Cannot upload invalid Notebook" -msgstr "Impossible de téléverser un Notebook invalide" - -#: notebook/static/tree/js/notebooklist.js:1395 -#, python-format -msgid "There is already a file named \"%s\". Do you want to replace it?" -msgstr "Il y a déjà un fichier nommé « %s ». Souhaitez-vous le remplacer ?" - -#: notebook/static/tree/js/notebooklist.js:1397 -msgid "Replace file" -msgstr "Remplacer le fichier" diff --git a/notebook/i18n/fr_FR/LC_MESSAGES/nbui.po b/notebook/i18n/fr_FR/LC_MESSAGES/nbui.po deleted file mode 100644 index 7cad18a34..000000000 --- a/notebook/i18n/fr_FR/LC_MESSAGES/nbui.po +++ /dev/null @@ -1,745 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2018-08-29 17:49+0200\n" -"PO-Revision-Date: 2018-09-15 17:55+0200\n" -"Last-Translator: Jocelyn Delalande \n" -"Language-Team: \n" -"Language: fr_FR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" -"X-Generator: Poedit 1.8.11\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "Vous demandez une page qui n'existe pas !" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "mode actuel" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "Fichier" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "Nouveau" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "Enregistrer" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "Renommer" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "Télécharger" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "Édition" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "Rechercher" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "Rechercher & Remplacer" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "Raccourcis clavier" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "Par Défaut" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "Sublime Text" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "Affichage" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "Afficher/Masquer le logo et le titre du notebook (au-dessus de la " -"barre de menu)" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "Afficher/Masquer l'en-tête" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "Afficher/Masquer les numéros de ligne" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "Langage" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "L'erreur était :" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "Mot de passe ou jeton:" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "Mot de passe :" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "Se connecter" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "Connexion non disponible, vous ne devriez pas voir cette page." - -#: notebook/templates/logout.html:24 -#, python-format -msgid "Proceed to the dashboard" -msgstr "Continuer vers le tableau de bord" - -#: notebook/templates/logout.html:26 -#, python-format -msgid "Proceed to the login page" -msgstr "Continuer vers la page de connexion" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "Menu" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "Noyau" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "Ce notebook est en lecture seule" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "Nouveau Notebook" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "Ouvre une nouvelle fenêtre de tableau de bord" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "Ouvrir..." - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "Ouvrir une copie du contenu de ce notebook et démarrer un nouveau noyau" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "Faire une copie..." - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "Renommer..." - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "Créer une nouvelle sauvegarde" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "Restaurer la sauvegarde" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "Imprimer l'aperçu" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "Télécharger au format" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "Notebook (.ipynb)" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "Script" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "HTML (.html)" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "Markdown (.md)" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "reST (.rst)" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "LaTeX (.tex)" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "PDF via LaTeX (.pdf)" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "Déployer en tant que" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "Faire confiance à la sortie de ce notebook" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "Faire confiance au notebook" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "Arrêter le noyau de ce notebook et fermer cette fenêtre" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "Fermer et arrêter" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "Couper les cellules" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "Copier les cellules" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "Coller les cellules avant" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "Coller les cellules après" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "Coller les cellules & remplacer" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "Supprimer les cellules" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "Annuler la suppression des cellules" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "Diviser la cellule" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "Fusionner avec la cellule précédente" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "Fusionner avec la cellule suivante" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "Déplacer la cellule vers le haut" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "Déplacer la cellule vers le bas" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "Éditer les méta-données du notebook" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "Rechercher et remplacer" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "Couper les pièces-Jointes de la cellule" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "Copier les pièces-jointes de la cellule" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "Coller les pièces-jointes de la cellule" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "Insérer une image" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "Afficher/Masquer les icônes d'action (en-dessous de la barre de menu)" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "Afficher/Masquer la barre d'outils" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "Afficher/Masquer les numéros de ligne dans les cellules" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "Barre d'outil de cellule" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "Insérer" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "Insérer une cellule de code vide avant de la cellule active" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "Insérer une cellule avant" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "Insérer une cellule de code vide après la cellule active" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "Insérer une cellule après" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "Cellule" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "Exécuter cette cellule, et déplacer le curseur à la suivante" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "Exécuter les cellules" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "Exécuter cette cellule, sélectionner la suivante" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "Exécuter les cellules et sélectionner la suivante" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "Exécuter la cellule et insérer à la suite" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "Exécuter les cellules et insérer après" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "Exécuter toutes les cellules du notebook" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "Exécuter tout" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "Exécuter toutes les cellules avant celle-ci (non incluse)" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "Exécuter toutes les précédentes" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "Exécuter cette cellule et toutes les suivantes" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "Exécuter toutes les suivantes" - -#: notebook/templates/notebook.html:205 -msgid "" -"All cells in the notebook have a cell type. By default, new cells are " -"created as 'Code' cells" -msgstr "" -"Toutes les cellules dans le notebook ont un type de " -"cellule. Par défaut, les nouvelles cellules sont de type 'Code'" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "Type de cellule" - -#: notebook/templates/notebook.html:209 -msgid "" -"Contents will be sent to the kernel for execution, and output will display " -"in the footer of cell" -msgstr "" -"Le contenu sera envoyé au noyau pour exécution, et la sortie sera affichée " -"dans le pied de cellule" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "" -"Le contenu sera rendu en tant que HTML afin de servir de texte explicatif" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "Le contenu passera par nbconvert qui ne l'altèrera pas" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "Texte Brut (pour NBConvert)" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "Sorties actuelles" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "Masquer/Afficher la sortie de la cellule actuelle" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "Afficher/Masquer" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "Faire défiler la sortie de la cellule actuelle" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "Activer/Désactiver le défilement" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "Effacer la sortie de la cellule actuelle" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "Effacer" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "Toute la sortie" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "Afficher/Masquer la sortie de toutes les cellules" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "Faire défiler la sortie de toutes les cellules" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "Effacer la sortie de toutes les cellules" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "Envoyer l'interruption clavier (CTRL-C) au noyau" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "Interrompre" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "Redémarrer le noyau" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "Redémarrer" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "Redémarrer le noyau et effacer toutes les sorties" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "Redémarrer & effacer les sorties" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "Redémarrer le noyau et ré-exécuter le noteboook" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "Redémarrer & tout exécuter" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "Reconnecter au noyau" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "Reconnecter" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "Changer de noyau" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "Aide" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "Une rapide visite de l'interface utilisateur du notebook" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "Visite de l'interface utilisateur" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "Ouvre une infobulle listant tous les raccourcis clavier" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "Raccourcis clavier" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "Ouvre une boîte de dialogue permettant de modifier les raccourcis clavier" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "Editer les raccourcis clavier" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "Aide notebook" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "S'ouvre dans une nouvelle fenêtre" - -#: notebook/templates/notebook.html:319 -msgid "About Jupyter Notebook" -msgstr "À propos de Jupyter Notebook" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "À propos" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "Jupyter Notebook nécessite JavaScript" - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "Merci de l'activer pour continuer." - -#: notebook/templates/page.html:121 -msgid "dashboard" -msgstr "tableau de bord" - -#: notebook/templates/page.html:132 -msgid "Logout" -msgstr "Se déconnecter" - -#: notebook/templates/page.html:134 -msgid "Login" -msgstr "Se connecter" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "Fichiers" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "Actifs" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "Grappes" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "Sélectionner des éléments pour leur appliquer des actions." - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "Dupliquer la sélection" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "Dupliquer" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "Renommer la sélection" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "Déplacer la sélection" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "Déplacer" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "Télécharger la sélection" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "Arrêter le(s) notebook(s) sélectionné(s)" - -#: notebook/templates/notebook.html:278 notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "Arrêter" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "Voir la sélection" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "Éditer la sélection" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "Supprimer la sélection" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "Cliquer pour choisir un fichier à téléverser" - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "Téléverser" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "Fichier texte" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "Répertoire" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "Terminal" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "Terminaux non disponibles" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "Rafraîchir la liste des notebooks" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "Sélectionner tout / aucun" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "Sélectionner..." - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "Sélectionner tous les répertoires" - -#: notebook/templates/tree.html:98 -msgid "Folders" -msgstr "Répertoires" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "Sélectionner tous les notebooks" - -#: notebook/templates/tree.html:99 -msgid "All Notebooks" -msgstr "Tous les notebooks" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "Sélectionner les notebooks en cours d'exécution" - -#: notebook/templates/tree.html:100 -msgid "Running" -msgstr "Actifs" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "Sélectionner tous les fichiers" - -#: notebook/templates/tree.html:101 -msgid "Files" -msgstr "Fichiers" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "Dernière modification" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "Nom" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "Processus Jupyter en cours d'exécution" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "Rafraîchir la liste des actifs" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "Il n'y a aucun terminal en cours d'exécution." - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "Les terminaux sont indisponibles." - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "Notebooks" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "Il n'y a aucun notebook en cours d'exécution." - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "L'onglet des grappes est désormais fourni par IPython parallel." - -#: notebook/templates/tree.html:179 -msgid "" -"See 'IPython parallel' for installation details." -msgstr "" -"Voir 'IPython parallel' pour les détails d'installation." diff --git a/notebook/i18n/fr_FR/LC_MESSAGES/notebook.po b/notebook/i18n/fr_FR/LC_MESSAGES/notebook.po deleted file mode 100644 index 5437b1b0f..000000000 --- a/notebook/i18n/fr_FR/LC_MESSAGES/notebook.po +++ /dev/null @@ -1,480 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-08 21:52-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/notebookapp.py:53 -msgid "The Jupyter Notebook requires tornado >= 4.0" -msgstr "" - -#: notebook/notebookapp.py:57 -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "" - -#: notebook/notebookapp.py:59 -#, python-format -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have %s" -msgstr "" - -#: notebook/notebookapp.py:209 -msgid "The `ignore_minified_js` flag is deprecated and no longer works." -msgstr "" - -#: notebook/notebookapp.py:210 -#, python-format -msgid "Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "" - -#: notebook/notebookapp.py:211 -msgid "The `ignore_minified_js` flag is deprecated and will be removed in Notebook 6.0" -msgstr "" - -#: notebook/notebookapp.py:389 -msgid "List currently running notebook servers." -msgstr "" - -#: notebook/notebookapp.py:393 -msgid "Produce machine-readable JSON output." -msgstr "" - -#: notebook/notebookapp.py:397 -msgid "If True, each line of output will be a JSON object with the details from the server info file." -msgstr "" - -#: notebook/notebookapp.py:402 -msgid "Currently running servers:" -msgstr "" - -#: notebook/notebookapp.py:419 -msgid "Don't open the notebook in a browser after startup." -msgstr "" - -#: notebook/notebookapp.py:423 -msgid "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "" - -#: notebook/notebookapp.py:439 -msgid "Allow the notebook to be run from root user." -msgstr "" - -#: notebook/notebookapp.py:470 -msgid "" -"The Jupyter HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client." -msgstr "" - -#: notebook/notebookapp.py:509 -msgid "Deprecated: Use minified JS file or not, mainly use during dev to avoid JS recompilation" -msgstr "" - -#: notebook/notebookapp.py:540 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "" - -#: notebook/notebookapp.py:544 -msgid "Whether to allow the user to run the notebook as root." -msgstr "" - -#: notebook/notebookapp.py:548 -msgid "The default URL to redirect to from `/`" -msgstr "" - -#: notebook/notebookapp.py:552 -msgid "The IP address the notebook server will listen on." -msgstr "" - -#: notebook/notebookapp.py:565 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "" - -#: notebook/notebookapp.py:579 -msgid "The port the notebook server will listen on." -msgstr "" - -#: notebook/notebookapp.py:583 -msgid "The number of additional ports to try if the specified port is not available." -msgstr "" - -#: notebook/notebookapp.py:587 -msgid "The full path to an SSL/TLS certificate file." -msgstr "" - -#: notebook/notebookapp.py:591 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "" - -#: notebook/notebookapp.py:595 -msgid "The full path to a certificate authority certificate for SSL/TLS client authentication." -msgstr "" - -#: notebook/notebookapp.py:599 -msgid "The file where the cookie secret is stored." -msgstr "" - -#: notebook/notebookapp.py:628 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "" - -#: notebook/notebookapp.py:635 -#, python-format -msgid "Could not set permissions on %s" -msgstr "" - -#: notebook/notebookapp.py:640 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:650 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:726 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:737 -msgid "DEPRECATED, use tornado_settings" -msgstr "" - -#: notebook/notebookapp.py:742 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "" - -#: notebook/notebookapp.py:746 -msgid "Supply overrides for the tornado.web.Application that the Jupyter notebook uses." -msgstr "" - -#: notebook/notebookapp.py:750 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:761 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" - -#: notebook/notebookapp.py:764 -msgid "Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details." -msgstr "" - -#: notebook/notebookapp.py:768 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" - -#: notebook/notebookapp.py:772 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "" - -#: notebook/notebookapp.py:776 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "" - -#: notebook/notebookapp.py:812 -msgid "DEPRECATED use base_url" -msgstr "" - -#: notebook/notebookapp.py:816 -msgid "base_project_url is deprecated, use base_url" -msgstr "" - -#: notebook/notebookapp.py:832 -msgid "Path to search for custom.js, css" -msgstr "" - -#: notebook/notebookapp.py:844 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "" - -#: notebook/notebookapp.py:855 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "" - -#: notebook/notebookapp.py:900 -#, python-format -msgid "Using MathJax: %s" -msgstr "" - -#: notebook/notebookapp.py:903 -msgid "The MathJax.js configuration file that is to be used." -msgstr "" - -#: notebook/notebookapp.py:908 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "" - -#: notebook/notebookapp.py:914 -msgid "The notebook manager class to use." -msgstr "" - -#: notebook/notebookapp.py:920 -msgid "The kernel manager class to use." -msgstr "" - -#: notebook/notebookapp.py:926 -msgid "The session manager class to use." -msgstr "" - -#: notebook/notebookapp.py:932 -msgid "The config manager class to use" -msgstr "" - -#: notebook/notebookapp.py:953 -msgid "The login handler class to use." -msgstr "" - -#: notebook/notebookapp.py:960 -msgid "The logout handler class to use." -msgstr "" - -#: notebook/notebookapp.py:964 -msgid "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL" -msgstr "" - -#: notebook/notebookapp.py:976 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:988 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "" - -#: notebook/notebookapp.py:990 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "" - -#: notebook/notebookapp.py:995 -msgid "The directory to use for notebooks and kernels." -msgstr "" - -#: notebook/notebookapp.py:1018 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "" - -#: notebook/notebookapp.py:1031 -msgid "DEPRECATED use the nbserver_extensions dict instead" -msgstr "" - -#: notebook/notebookapp.py:1036 -msgid "server_extensions is deprecated, use nbserver_extensions" -msgstr "" - -#: notebook/notebookapp.py:1040 -msgid "Dict of Python modules to load as notebook server extensions.Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order." -msgstr "" - -#: notebook/notebookapp.py:1049 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "" - -#: notebook/notebookapp.py:1052 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/notebookapp.py:1056 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/notebookapp.py:1060 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "" - -#: notebook/notebookapp.py:1071 -#, python-format -msgid "No such file or directory: %s" -msgstr "" - -#: notebook/notebookapp.py:1141 -msgid "Notebook servers are configured to only be run with a password." -msgstr "" - -#: notebook/notebookapp.py:1142 -msgid "Hint: run the following command to set a password" -msgstr "" - -#: notebook/notebookapp.py:1143 -msgid "\t$ python -m notebook.auth password" -msgstr "" - -#: notebook/notebookapp.py:1181 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "" - -#: notebook/notebookapp.py:1184 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "" - -#: notebook/notebookapp.py:1193 -msgid "ERROR: the notebook server could not be started because no available port could be found." -msgstr "" - -#: notebook/notebookapp.py:1199 -msgid "[all ip addresses on your system]" -msgstr "" - -#: notebook/notebookapp.py:1223 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "" - -#: notebook/notebookapp.py:1259 -msgid "interrupted" -msgstr "" - -#: notebook/notebookapp.py:1261 -msgid "y" -msgstr "" - -#: notebook/notebookapp.py:1262 -msgid "n" -msgstr "" - -#: notebook/notebookapp.py:1263 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "" - -#: notebook/notebookapp.py:1269 -msgid "Shutdown confirmed" -msgstr "" - -#: notebook/notebookapp.py:1273 -msgid "No answer for 5s:" -msgstr "" - -#: notebook/notebookapp.py:1274 -msgid "resuming operation..." -msgstr "" - -#: notebook/notebookapp.py:1282 -#, python-format -msgid "received signal %s, stopping" -msgstr "" - -#: notebook/notebookapp.py:1338 -#, python-format -msgid "Error loading server extension %s" -msgstr "" - -#: notebook/notebookapp.py:1369 -#, python-format -msgid "Shutting down %d kernels" -msgstr "" - -#: notebook/notebookapp.py:1375 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "" -msgstr[1] "" - -#: notebook/notebookapp.py:1379 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"\r" -"%s" -msgstr "" - -#: notebook/notebookapp.py:1426 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "" - -#: notebook/notebookapp.py:1432 -msgid "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." -msgstr "" - -#: notebook/notebookapp.py:1434 -msgid "Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at http://jupyter.org/community.html." -msgstr "" - -#: notebook/notebookapp.py:1445 -#, python-format -msgid "No web browser found: %s." -msgstr "" - -#: notebook/notebookapp.py:1450 -#, python-format -msgid "%s does not exist" -msgstr "" - -#: notebook/notebookapp.py:1484 -msgid "Interrupted..." -msgstr "" - -#: notebook/services/contents/filemanager.py:506 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "" - -#: notebook/services/contents/manager.py:68 -msgid "Untitled" -msgstr "" - diff --git a/notebook/i18n/ja_JP/LC_MESSAGES/nbjs.po b/notebook/i18n/ja_JP/LC_MESSAGES/nbjs.po deleted file mode 100644 index aea692a16..000000000 --- a/notebook/i18n/ja_JP/LC_MESSAGES/nbjs.po +++ /dev/null @@ -1,1934 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-06-27 14:04-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/static/base/js/dialog.js:161 -msgid "Manually edit the JSON below to manipulate the metadata for this cell." -msgstr "このセルのメタデータを操作するには以下のJSONを手動で編集してください。" - -#: notebook/static/base/js/dialog.js:163 -msgid "Manually edit the JSON below to manipulate the metadata for this notebook." -msgstr "このノートブックのメタデータを操作するには以下のJSONを手動で編集してください。" - -#: notebook/static/base/js/dialog.js:165 -msgid " We recommend putting custom metadata attributes in an appropriately named substructure, so they don't conflict with those of others." -msgstr " カスタムメタデータ属性は適切な名前のサブ構造に含め他の属性と競合しないようにすることをお勧めします。" - -#: notebook/static/base/js/dialog.js:180 -msgid "Edit the metadata" -msgstr "メタデータの編集" - -#: notebook/static/base/js/dialog.js:202 -msgid "Edit Notebook Metadata" -msgstr "ノートブックのメタデータを編集" - -#: notebook/static/base/js/dialog.js:204 -msgid "Edit Cell Metadata" -msgstr "セルのメタデータを編集" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/notebook.js:475 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:859 -#: notebook/static/tree/js/notebooklist.js:1418 -msgid "Cancel" -msgstr "キャンセル" - -#: notebook/static/base/js/dialog.js:208 -msgid "Edit" -msgstr "編集" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/kernelselector.js:278 -#: notebook/static/notebook/js/mathjaxutils.js:42 -#: notebook/static/notebook/js/notebook.js:469 -#: notebook/static/notebook/js/notificationarea.js:187 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/newnotebook.js:97 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "OK" -msgstr "OK" - -#: notebook/static/base/js/dialog.js:208 -msgid "Apply" -msgstr "適用" - -#: notebook/static/base/js/dialog.js:225 -msgid "WARNING: Could not save invalid JSON." -msgstr "警告: 不正な JSON のため保存できませんでした。" - -#: notebook/static/base/js/dialog.js:247 -msgid "There are no attachments for this cell." -msgstr "このセルには添付ファイルはありません。" - -#: notebook/static/base/js/dialog.js:250 -msgid "Current cell attachments" -msgstr "現在のセルの添付ファイル" - -#: notebook/static/base/js/dialog.js:259 -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:46 -msgid "Attachments" -msgstr "添付ファイル" - -#: notebook/static/base/js/dialog.js:283 -msgid "Restore" -msgstr "復元" - -#: notebook/static/base/js/dialog.js:293 -#: notebook/static/tree/js/notebooklist.js:1018 -msgid "Delete" -msgstr "削除" - -#: notebook/static/base/js/dialog.js:342 notebook/static/base/js/dialog.js:386 -msgid "Edit attachments" -msgstr "添付ファイルを編集" - -#: notebook/static/base/js/dialog.js:348 -msgid "Edit Notebook Attachments" -msgstr "ノートブックの添付ファイルを編集" - -#: notebook/static/base/js/dialog.js:350 -msgid "Edit Cell Attachments" -msgstr "セルの添付ファイルを編集" - -#: notebook/static/base/js/dialog.js:373 -msgid "Select a file to insert." -msgstr "挿入するファイルを選択して下さい。" - -#: notebook/static/base/js/dialog.js:399 -msgid "Select a file" -msgstr "ファイルを選択" - -#: notebook/static/notebook/js/about.js:14 -msgid "You are using Jupyter notebook." -msgstr "Jupyter notebook を使用しています。" - -#: notebook/static/notebook/js/about.js:16 -msgid "The version of the notebook server is: " -msgstr "ノートブックサーバのバージョン" - -#: notebook/static/notebook/js/about.js:22 -msgid "The server is running on this version of Python:" -msgstr "サーバはこのバージョンの Python で稼働しています:" - -#: notebook/static/notebook/js/about.js:25 -msgid "Waiting for kernel to be available..." -msgstr "利用可能なカーネルを待機しています..." - -#: notebook/static/notebook/js/about.js:27 -msgid "Server Information:" -msgstr "サーバ情報:" - -#: notebook/static/notebook/js/about.js:29 -msgid "Current Kernel Information:" -msgstr "現在のカーネル情報:" - -#: notebook/static/notebook/js/about.js:32 -msgid "Could not access sys_info variable for version information." -msgstr "バージョン情報のための sys_info 変数にアクセスできませんでした。" - -#: notebook/static/notebook/js/about.js:34 -msgid "Cannot find sys_info!" -msgstr "sys_info が見つかりません!" - -#: notebook/static/notebook/js/about.js:38 -msgid "About Jupyter Notebook" -msgstr "Jupyter Notebook について" - -#: notebook/static/notebook/js/about.js:47 -msgid "unable to contact kernel" -msgstr "kernel と通信できません" - -#: notebook/static/notebook/js/actions.js:69 -msgid "toggle rtl layout" -msgstr "rtl レイアウトをトグル" - -#: notebook/static/notebook/js/actions.js:70 -msgid "Toggle the screen directionality between left-to-right and right-to-left" -msgstr "画面の表示方向を、左から右、と右から左、でトグル" - -#: notebook/static/notebook/js/actions.js:76 -msgid "edit command mode keyboard shortcuts" -msgstr "コマンドモードキーボードショートカットを編集" - -#: notebook/static/notebook/js/actions.js:77 -msgid "Open a dialog to edit the command mode keyboard shortcuts" -msgstr "コマンドモードのキーボードショートカットを編集するためにダイアログを開きます" - -#: notebook/static/notebook/js/actions.js:97 -msgid "restart kernel" -msgstr "カーネルを再起動" - -#: notebook/static/notebook/js/actions.js:98 -msgid "restart the kernel (no confirmation dialog)" -msgstr "カーネルを再起動 (確認ダイアログ無し)" - -#: notebook/static/notebook/js/actions.js:106 -msgid "confirm restart kernel" -msgstr "カーネルを再起動の確認" - -#: notebook/static/notebook/js/actions.js:107 -msgid "restart the kernel (with dialog)" -msgstr "カーネルを再起動 (確認ダイアログあり)" - -#: notebook/static/notebook/js/actions.js:113 -msgid "restart kernel and run all cells" -msgstr "カーネルを再起動し全てのセルを実行" - -#: notebook/static/notebook/js/actions.js:114 -msgid "restart the kernel, then re-run the whole notebook (no confirmation dialog)" -msgstr "カーネルを再起動しノートブック全体を再実行 (確認ダイアログ無し)" - -#: notebook/static/notebook/js/actions.js:120 -msgid "confirm restart kernel and run all cells" -msgstr "カーネルを再起動し全てのセルを実行する確認" - -#: notebook/static/notebook/js/actions.js:121 -msgid "restart the kernel, then re-run the whole notebook (with dialog)" -msgstr "カーネルを再起動しノートブック全体を再実行 (確認ダイアログあり)" - -#: notebook/static/notebook/js/actions.js:127 -msgid "restart kernel and clear output" -msgstr "カーネルを再起動し出力をクリア" - -#: notebook/static/notebook/js/actions.js:128 -msgid "restart the kernel and clear all output (no confirmation dialog)" -msgstr "カーネルを再起動し全ての出力をクリア (確認ダイアログ無し)" - -#: notebook/static/notebook/js/actions.js:134 -msgid "confirm restart kernel and clear output" -msgstr "カーネルを再起動し出力をクリアする確認" - -#: notebook/static/notebook/js/actions.js:135 -msgid "restart the kernel and clear all output (with dialog)" -msgstr "カーネルを再起動し出力をクリア (確認ダイアログあり)" - -#: notebook/static/notebook/js/actions.js:142 -#: notebook/static/notebook/js/actions.js:143 -msgid "interrupt the kernel" -msgstr "カーネルを中断" - -#: notebook/static/notebook/js/actions.js:150 -msgid "run cell and select next" -msgstr "セルを実行し次を選択" - -#: notebook/static/notebook/js/actions.js:152 -msgid "run cell, select below" -msgstr "セルを実行し下を選択" - -#: notebook/static/notebook/js/actions.js:159 -#: notebook/static/notebook/js/actions.js:160 -msgid "run selected cells" -msgstr "選択されているセルを実行" - -#: notebook/static/notebook/js/actions.js:167 -#: notebook/static/notebook/js/actions.js:168 -msgid "run cell and insert below" -msgstr "セルを実行し下に挿入" - -#: notebook/static/notebook/js/actions.js:175 -#: notebook/static/notebook/js/actions.js:176 -msgid "run all cells" -msgstr "全てのセルを実行" - -#: notebook/static/notebook/js/actions.js:183 -#: notebook/static/notebook/js/actions.js:184 -msgid "run all cells above" -msgstr "ここまでのセルを実行" - -#: notebook/static/notebook/js/actions.js:190 -#: notebook/static/notebook/js/actions.js:191 -msgid "run all cells below" -msgstr "以下の全てのセルを実行" - -#: notebook/static/notebook/js/actions.js:197 -#: notebook/static/notebook/js/actions.js:198 -msgid "enter command mode" -msgstr "コマンドラインモードに移る" - -#: notebook/static/notebook/js/actions.js:205 -#: notebook/static/notebook/js/actions.js:206 -msgid "insert image" -msgstr "画像の挿入" - -#: notebook/static/notebook/js/actions.js:213 -#: notebook/static/notebook/js/actions.js:214 -msgid "cut cell attachments" -msgstr "セルの添付ファイルを切り取り" - -#: notebook/static/notebook/js/actions.js:221 -#: notebook/static/notebook/js/actions.js:222 -msgid "copy cell attachments" -msgstr "セルの添付ファイルをコピー" - -#: notebook/static/notebook/js/actions.js:229 -#: notebook/static/notebook/js/actions.js:230 -msgid "paste cell attachments" -msgstr "セルの添付ファイルをペースト" - -#: notebook/static/notebook/js/actions.js:237 -#: notebook/static/notebook/js/actions.js:238 -msgid "split cell at cursor" -msgstr "カーソル位置でセルを分割" - -#: notebook/static/notebook/js/actions.js:245 -#: notebook/static/notebook/js/actions.js:246 -msgid "enter edit mode" -msgstr "編集モードに移る" - -#: notebook/static/notebook/js/actions.js:253 -msgid "select previous cell" -msgstr "1つ前のセルを選択" - -#: notebook/static/notebook/js/actions.js:254 -msgid "select cell above" -msgstr "上のセルを選択" - -#: notebook/static/notebook/js/actions.js:265 -msgid "select next cell" -msgstr "次のセルを選択" - -#: notebook/static/notebook/js/actions.js:266 -msgid "select cell below" -msgstr "下のセルを選択" - -#: notebook/static/notebook/js/actions.js:277 -msgid "extend selection above" -msgstr "選択を上に拡大" - -#: notebook/static/notebook/js/actions.js:278 -msgid "extend selected cells above" -msgstr "セルの選択を上に拡大" - -#: notebook/static/notebook/js/actions.js:289 -msgid "extend selection below" -msgstr "選択を下に拡大" - -#: notebook/static/notebook/js/actions.js:290 -msgid "extend selected cells below" -msgstr "セルの選択を下に拡大" - -#: notebook/static/notebook/js/actions.js:301 -#: notebook/static/notebook/js/actions.js:302 -msgid "cut selected cells" -msgstr "選択されているセルを切り取り" - -#: notebook/static/notebook/js/actions.js:312 -#: notebook/static/notebook/js/actions.js:313 -msgid "copy selected cells" -msgstr "選択されているセルをコピー" - -#: notebook/static/notebook/js/actions.js:327 -#: notebook/static/notebook/js/actions.js:328 -msgid "paste cells above" -msgstr "上にセルをペースト" - -#: notebook/static/notebook/js/actions.js:335 -#: notebook/static/notebook/js/actions.js:336 -msgid "paste cells below" -msgstr "下にセルをペースト" - -#: notebook/static/notebook/js/actions.js:344 -#: notebook/static/notebook/js/actions.js:345 -msgid "insert cell above" -msgstr "上にセルを追加" - -#: notebook/static/notebook/js/actions.js:354 -#: notebook/static/notebook/js/actions.js:355 -msgid "insert cell below" -msgstr "下にセルを追加" - -#: notebook/static/notebook/js/actions.js:365 -#: notebook/static/notebook/js/actions.js:366 -msgid "change cell to code" -msgstr "セルをコードに変更" - -#: notebook/static/notebook/js/actions.js:373 -#: notebook/static/notebook/js/actions.js:374 -msgid "change cell to markdown" -msgstr "セルを markdown に変更" - -#: notebook/static/notebook/js/actions.js:381 -#: notebook/static/notebook/js/actions.js:382 -msgid "change cell to raw" -msgstr "セルを raw に変更" - -#: notebook/static/notebook/js/actions.js:389 -#: notebook/static/notebook/js/actions.js:390 -msgid "change cell to heading 1" -msgstr "セルを表題1に変更" - -#: notebook/static/notebook/js/actions.js:397 -#: notebook/static/notebook/js/actions.js:398 -msgid "change cell to heading 2" -msgstr "セルを表題2に変更" - -#: notebook/static/notebook/js/actions.js:405 -#: notebook/static/notebook/js/actions.js:406 -msgid "change cell to heading 3" -msgstr "セルを表題3に変更" - -#: notebook/static/notebook/js/actions.js:413 -#: notebook/static/notebook/js/actions.js:414 -msgid "change cell to heading 4" -msgstr "セルを表題4に変更" - -#: notebook/static/notebook/js/actions.js:421 -#: notebook/static/notebook/js/actions.js:422 -msgid "change cell to heading 5" -msgstr "セルを表題5に変更" - -#: notebook/static/notebook/js/actions.js:429 -#: notebook/static/notebook/js/actions.js:430 -msgid "change cell to heading 6" -msgstr "セルを表題6に変更" - -#: notebook/static/notebook/js/actions.js:437 -msgid "toggle cell output" -msgstr "セルの出力をトグル" - -#: notebook/static/notebook/js/actions.js:438 -msgid "toggle output of selected cells" -msgstr "選択中のセルの出力をトグル" - -#: notebook/static/notebook/js/actions.js:445 -msgid "toggle cell scrolling" -msgstr "セルのスクロールをトグル" - -#: notebook/static/notebook/js/actions.js:446 -msgid "toggle output scrolling of selected cells" -msgstr "選択中のセルの出力スクロールをトグル" - -#: notebook/static/notebook/js/actions.js:453 -msgid "clear cell output" -msgstr "セルの出力をクリア" - -#: notebook/static/notebook/js/actions.js:454 -msgid "clear output of selected cells" -msgstr "選択しているセルの出力をクリア" - -#: notebook/static/notebook/js/actions.js:460 -msgid "move cells down" -msgstr "セルを下に移動" - -#: notebook/static/notebook/js/actions.js:461 -msgid "move selected cells down" -msgstr "選択しているセルを下に移動" - -#: notebook/static/notebook/js/actions.js:469 -msgid "move cells up" -msgstr "セルを上に移動" - -#: notebook/static/notebook/js/actions.js:470 -msgid "move selected cells up" -msgstr "選択しているセルを上に移動" - -#: notebook/static/notebook/js/actions.js:478 -#: notebook/static/notebook/js/actions.js:479 -msgid "toggle line numbers" -msgstr "行番号をトグル" - -#: notebook/static/notebook/js/actions.js:486 -#: notebook/static/notebook/js/actions.js:487 -msgid "show keyboard shortcuts" -msgstr "キーボードショートカットを表示" - -#: notebook/static/notebook/js/actions.js:494 -msgid "delete cells" -msgstr "セルを削除" - -#: notebook/static/notebook/js/actions.js:495 -msgid "delete selected cells" -msgstr "選択されているセルを削除" - -#: notebook/static/notebook/js/actions.js:502 -#: notebook/static/notebook/js/actions.js:503 -msgid "undo cell deletion" -msgstr "セルの削除を取り消す" - -#: notebook/static/notebook/js/actions.js:512 -msgid "merge cell with previous cell" -msgstr "1つ前のアクティブセルとマージ" - -#: notebook/static/notebook/js/actions.js:513 -msgid "merge cell above" -msgstr "上のセルとマージ" - -#: notebook/static/notebook/js/actions.js:519 -msgid "merge cell with next cell" -msgstr "次のセルとマージ" - -#: notebook/static/notebook/js/actions.js:520 -msgid "merge cell below" -msgstr "下のセルとマージ" - -#: notebook/static/notebook/js/actions.js:527 -#: notebook/static/notebook/js/actions.js:528 -msgid "merge selected cells" -msgstr "選択されているセルをマージ" - -#: notebook/static/notebook/js/actions.js:535 -msgid "merge cells" -msgstr "セルをマージ" - -#: notebook/static/notebook/js/actions.js:536 -msgid "merge selected cells, or current cell with cell below if only one cell is selected" -msgstr "選択中のセル、または選択されていない場合は現在のセル以降をマージする" - -#: notebook/static/notebook/js/actions.js:549 -msgid "show command pallette" -msgstr "コマンドパレットの表示" - -#: notebook/static/notebook/js/actions.js:550 -msgid "open the command palette" -msgstr "コマンドパレットを開く" - -#: notebook/static/notebook/js/actions.js:557 -msgid "toggle all line numbers" -msgstr "全ての行番号をトグル" - -#: notebook/static/notebook/js/actions.js:558 -msgid "toggles line numbers in all cells, and persist the setting" -msgstr "全てのセルの行番号をトグルし設定を保存" - -#: notebook/static/notebook/js/actions.js:569 -msgid "show all line numbers" -msgstr "全ての行番号を保存" - -#: notebook/static/notebook/js/actions.js:570 -msgid "show line numbers in all cells, and persist the setting" -msgstr "全てのセルで行番号を表示し設定を保存" - -#: notebook/static/notebook/js/actions.js:579 -msgid "hide all line numbers" -msgstr "全ての行番号を非表示" - -#: notebook/static/notebook/js/actions.js:580 -msgid "hide line numbers in all cells, and persist the setting" -msgstr "すべてのセルの行番号を非表示にし設定を保持します" - -#: notebook/static/notebook/js/actions.js:589 -msgid "toggle header" -msgstr "ヘッダをトグル" - -#: notebook/static/notebook/js/actions.js:590 -msgid "switch between showing and hiding the header" -msgstr "ヘッダの表示と非表示を切り替えます" - -#: notebook/static/notebook/js/actions.js:605 -#: notebook/static/notebook/js/actions.js:606 -msgid "show the header" -msgstr "ヘッダを表示" - -#: notebook/static/notebook/js/actions.js:615 -#: notebook/static/notebook/js/actions.js:616 -msgid "hide the header" -msgstr "ヘッダを非表示" - -#: notebook/static/notebook/js/actions.js:646 -msgid "toggle toolbar" -msgstr "ツールバーをトグル" - -#: notebook/static/notebook/js/actions.js:647 -msgid "switch between showing and hiding the toolbar" -msgstr "ツールバーの表示と非表示を切り替える" - -#: notebook/static/notebook/js/actions.js:660 -#: notebook/static/notebook/js/actions.js:661 -msgid "show the toolbar" -msgstr "ツールバーを表示" - -#: notebook/static/notebook/js/actions.js:669 -#: notebook/static/notebook/js/actions.js:670 -msgid "hide the toolbar" -msgstr "ツールバーを非表示" - -#: notebook/static/notebook/js/actions.js:678 -#: notebook/static/notebook/js/actions.js:679 -msgid "close the pager" -msgstr "ページャを閉じる" - -#: notebook/static/notebook/js/actions.js:704 -msgid "ignore" -msgstr "無視" - -#: notebook/static/notebook/js/actions.js:710 -#: notebook/static/notebook/js/actions.js:711 -msgid "move cursor up" -msgstr "カーソルを上に移動" - -#: notebook/static/notebook/js/actions.js:731 -#: notebook/static/notebook/js/actions.js:732 -msgid "move cursor down" -msgstr "カーソルを下に移動" - -#: notebook/static/notebook/js/actions.js:750 -#: notebook/static/notebook/js/actions.js:751 -msgid "scroll notebook down" -msgstr "ノートブックを下にスクロール" - -#: notebook/static/notebook/js/actions.js:760 -#: notebook/static/notebook/js/actions.js:761 -msgid "scroll notebook up" -msgstr "ノートブックを上にスクロール" - -#: notebook/static/notebook/js/actions.js:770 -msgid "scroll cell center" -msgstr "セルを中央までスクロール" - -#: notebook/static/notebook/js/actions.js:771 -msgid "Scroll the current cell to the center" -msgstr "現在のセルが中央になる様にスクロール" - -#: notebook/static/notebook/js/actions.js:781 -msgid "scroll cell top" -msgstr "セルを最上部までスクロール" - -#: notebook/static/notebook/js/actions.js:782 -msgid "Scroll the current cell to the top" -msgstr "現在のセルが最上部になる様にスクロール" - -#: notebook/static/notebook/js/actions.js:792 -msgid "duplicate notebook" -msgstr "ノートブックの複製" - -#: notebook/static/notebook/js/actions.js:793 -msgid "Create and open a copy of the current notebook" -msgstr "現在のノートブックのコピーを作成し開く" - -#: notebook/static/notebook/js/actions.js:799 -msgid "trust notebook" -msgstr "ノートブックを信頼" - -#: notebook/static/notebook/js/actions.js:800 -msgid "Trust the current notebook" -msgstr "現在のノートブックを信頼する" - -#: notebook/static/notebook/js/actions.js:806 -msgid "rename notebook" -msgstr "ノートブックをリネーム" - -#: notebook/static/notebook/js/actions.js:807 -msgid "Rename the current notebook" -msgstr "現在のノートブックをリネームする" - -#: notebook/static/notebook/js/actions.js:813 -msgid "toggle all cells output collapsed" -msgstr "" - -#: notebook/static/notebook/js/actions.js:814 -msgid "Toggle the hidden state of all output areas" -msgstr "" - -#: notebook/static/notebook/js/actions.js:820 -msgid "toggle all cells output scrolled" -msgstr "" - -#: notebook/static/notebook/js/actions.js:821 -msgid "Toggle the scrolling state of all output areas" -msgstr "" - -#: notebook/static/notebook/js/actions.js:828 -msgid "clear all cells output" -msgstr "全てのセル出力をクリア" - -#: notebook/static/notebook/js/actions.js:829 -msgid "Clear the content of all the outputs" -msgstr "全ての出力コンテンツをクリア" - -#: notebook/static/notebook/js/actions.js:835 -msgid "save notebook" -msgstr "ノートブックの保存" - -#: notebook/static/notebook/js/actions.js:836 -msgid "Save and Checkpoint" -msgstr "保存とチェックポイント" - -#: notebook/static/notebook/js/cell.js:79 -msgid "Warning: accessing Cell.cm_config directly is deprecated." -msgstr "警告: Cell.cm_config に直接アクセスすることは非推奨です。" - -#: notebook/static/notebook/js/cell.js:763 -#, python-format -msgid "Unrecognized cell type: %s" -msgstr "認識できないセル種別: %s" - -#: notebook/static/notebook/js/cell.js:777 -msgid "Unrecognized cell type" -msgstr "認識できないセル種別" - -#: notebook/static/notebook/js/celltoolbar.js:296 -#, python-format -msgid "Error in cell toolbar callback %s" -msgstr "セルツールバーのコールバック %s でエラー" - -#: notebook/static/notebook/js/clipboard.js:53 -#, python-format -msgid "Clipboard types: %s" -msgstr "クリップボードの種別: %s" - -#: notebook/static/notebook/js/clipboard.js:96 -msgid "Dialog for paste from system clipboard" -msgstr "システムのクリップボードから張り付け" - -#: notebook/static/notebook/js/clipboard.js:109 -msgid "Ctrl-V" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:111 -msgid "Cmd-V" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:113 -#, python-format -msgid "Press %s again to paste" -msgstr "ペーストするには %s をもう一度押します" - -#: notebook/static/notebook/js/clipboard.js:116 -msgid "Why is this needed? " -msgstr "これが必要ですか?" - -#: notebook/static/notebook/js/clipboard.js:118 -msgid "We can't get paste events in this browser without a text box. " -msgstr "このブラウザではテキストボックスなしに貼り付けイベントを受け取ることができません。" - -#: notebook/static/notebook/js/clipboard.js:119 -msgid "There's an invisible text box focused in this dialog." -msgstr "このダイアログには目に見えないテキストボックスがあります。" - -#: notebook/static/notebook/js/clipboard.js:125 -#, python-format -msgid "%s to paste" -msgstr "ペーストするには %s" - -#: notebook/static/notebook/js/codecell.js:310 -msgid "Can't execute cell since kernel is not set." -msgstr "カーネルが存在しないのでセルを実行できません。" - -#: notebook/static/notebook/js/codecell.js:472 -msgid "In" -msgstr "入力" - -#: notebook/static/notebook/js/kernelselector.js:269 -#, python-format -msgid "Could not find a kernel matching %s. Please select a kernel:" -msgstr "%s にマッチするカーネルが見つかりませんでした。カーネルを選択して下さい:" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Continue Without Kernel" -msgstr "カーネル無しで続行" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Set Kernel" -msgstr "カーネルの設定" - -#: notebook/static/notebook/js/kernelselector.js:281 -msgid "Kernel not found" -msgstr "カーネルが見つかりません" - -#: notebook/static/notebook/js/kernelselector.js:319 -#: notebook/static/tree/js/newnotebook.js:99 -msgid "Creating Notebook Failed" -msgstr "ノートブックの作成に失敗しました" - -#: notebook/static/notebook/js/kernelselector.js:320 -#: notebook/static/tree/js/notebooklist.js:1360 -#, python-format -msgid "The error was: %s" -msgstr "エラー: %s" - -#: notebook/static/notebook/js/maintoolbar.js:54 -msgid "Run" -msgstr "実行" - -#: notebook/static/notebook/js/maintoolbar.js:76 -msgid "Code" -msgstr "コード" - -#: notebook/static/notebook/js/maintoolbar.js:77 -msgid "Markdown" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:78 -msgid "Raw NBConvert" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:79 -msgid "Heading" -msgstr "ヘッダ" - -#: notebook/static/notebook/js/maintoolbar.js:115 -msgid "unrecognized cell type:" -msgstr "不明なセル種別:" - -#: notebook/static/notebook/js/mathjaxutils.js:45 -#, python-format -msgid "Failed to retrieve MathJax from '%s'" -msgstr "%s から MathJax を取得できませんでした" - -#: notebook/static/notebook/js/mathjaxutils.js:47 -msgid "Math/LaTeX rendering will be disabled." -msgstr "Math/LaTeX レンダリングは無効になります。" - -#: notebook/static/notebook/js/menubar.js:220 -msgid "Trusted Notebook" -msgstr "信頼されたノートブック" - -#: notebook/static/notebook/js/menubar.js:226 -msgid "Trust Notebook" -msgstr "ノートブックを信頼する" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16 -#: notebook/static/notebook/js/menubar.js:383 -msgid "None" -msgstr "" - -#: notebook/static/notebook/js/menubar.js:406 -msgid "No checkpoints" -msgstr "チェックポイントはありません" - -#: notebook/static/notebook/js/menubar.js:465 -msgid "Opens in a new window" -msgstr "新しいウィンドウで開く" - -#: notebook/static/notebook/js/notebook.js:431 -msgid "Autosave in progress, latest changes may be lost." -msgstr "自動保存が実行中です。最後の変更は失われるかもしれません。" - -#: notebook/static/notebook/js/notebook.js:433 -msgid "Unsaved changes will be lost." -msgstr "未保存の変更は破棄されます。" - -#: notebook/static/notebook/js/notebook.js:438 -msgid "The Kernel is busy, outputs may be lost." -msgstr "カーネルがビジーです。出力が欠けるかもしれません。" - -#: notebook/static/notebook/js/notebook.js:461 -msgid "This notebook is version %1$s, but we only fully support up to %2$s." -msgstr "このノートブックのバージョンは %1$s です。しかし完全なサポートは %2$s だけになります。" - -#: notebook/static/notebook/js/notebook.js:463 -msgid "You can still work with this notebook, but cell and output types introduced in later notebook versions will not be available." -msgstr "このノートブックはまだ動作しますがこれ以降のノートブックバージョンで導入されたセルおよび出力タイプは利用できなくなります。" - -#: notebook/static/notebook/js/notebook.js:470 -msgid "Restart and Run All Cells" -msgstr "再起動と全ての出力をクリア" - -#: notebook/static/notebook/js/notebook.js:471 -msgid "Restart and Clear All Outputs" -msgstr "再起動と全ての出力をクリア" - -#: notebook/static/notebook/js/notebook.js:472 -msgid "Restart" -msgstr "再起動" - -#: notebook/static/notebook/js/notebook.js:473 -msgid "Continue Running" -msgstr "実行を続行" - -#: notebook/static/notebook/js/notebook.js:474 -msgid "Reload" -msgstr "リロード" - -#: notebook/static/notebook/js/notebook.js:476 -msgid "Overwrite" -msgstr "上書き" - -#: notebook/static/notebook/js/notebook.js:477 -msgid "Trust" -msgstr "信頼" - -#: notebook/static/notebook/js/notebook.js:478 -msgid "Revert" -msgstr "復元" - -#: notebook/static/notebook/js/notebook.js:483 -msgid "Newer Notebook" -msgstr "新しいノートブック" - -#: notebook/static/notebook/js/notebook.js:1548 -msgid "Use markdown headings" -msgstr "Markdown のヘッダを使用" - -#: notebook/static/notebook/js/notebook.js:1550 -msgid "Jupyter no longer uses special heading cells. Instead, write your headings in Markdown cells using # characters:" -msgstr "Jupyter は特別な見出しセルを使用しなくなりました。代わりに # 文字を使用して Markdown セルに見出しを書きいて下さい:" - -#: notebook/static/notebook/js/notebook.js:1553 -msgid "## This is a level 2 heading" -msgstr "## これはレベル2のヘッダです" - -#: notebook/static/notebook/js/notebook.js:2248 -msgid "Restart kernel and re-run the whole notebook?" -msgstr "カーネルを再起動しノートブック全体を再実行する" - -#: notebook/static/notebook/js/notebook.js:2250 -msgid "Are you sure you want to restart the current kernel and re-execute the whole notebook? All variables and outputs will be lost." -msgstr "現在のカーネルを再起動してノートブック全体を再実行しますか?全ての変数と出力は失われます。" - -#: notebook/static/notebook/js/notebook.js:2275 -msgid "Restart kernel and clear all output?" -msgstr "カーネルを再起動し全ての出力をクリアしますか?" - -#: notebook/static/notebook/js/notebook.js:2277 -msgid "Do you want to restart the current kernel and clear all output? All variables and outputs will be lost." -msgstr "現在のカーネルを再起動してすべての出力をクリアしますか?全ての変数と出力は失われます。" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Restart kernel?" -msgstr "カーネルを再起動しますか?" - -#: notebook/static/notebook/js/notebook.js:2324 -msgid "Do you want to restart the current kernel? All variables will be lost." -msgstr "現在のカーネルを再起動しますか?全ての変数は失われます。" - -#: notebook/static/notebook/js/notebook.js:2320 -msgid "Shutdown kernel?" -msgstr "カーネルをシャットダウンしますか?" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Do you want to shutdown the current kernel? All variables will be lost." -msgstr "現在のカーネルをシャットダウンしますか?すべての変数は失われます。" - -#: notebook/static/notebook/js/notebook.js:2734 -msgid "Notebook changed" -msgstr "ノートブックは変更されました" - -#: notebook/static/notebook/js/notebook.js:2735 -msgid "The notebook file has changed on disk since the last time we opened or saved it. Do you want to overwrite the file on disk with the version open here, or load the version on disk (reload the page) ?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2782 -#: notebook/static/notebook/js/notebook.js:2990 -msgid "Notebook validation failed" -msgstr "ノートブックの検証に失敗しました" - -#: notebook/static/notebook/js/notebook.js:2785 -msgid "The save operation succeeded, but the notebook does not appear to be valid. The validation error was:" -msgstr "保存操作は成功しましたがノートブックは有効ではないようです。検証エラー:" - -#: notebook/static/notebook/js/notebook.js:2836 -msgid "A trusted Jupyter notebook may execute hidden malicious code when you open it. Selecting trust will immediately reload this notebook in a trusted state. For more information, see the Jupyter security documentation: " -msgstr "信頼された Jupyter ノートブックは開いた際に隠された悪意のあるコードが実行される可能性があります。信頼を選択すると直ちにリロードされこのノートブックは信頼できる状態になりします。詳細については、Jupyter のセキュリティドキュメントを参照してください。" - -#: notebook/static/notebook/js/notebook.js:2840 -msgid "here" -msgstr "ここ" - -#: notebook/static/notebook/js/notebook.js:2848 -msgid "Trust this notebook?" -msgstr "このノートブックを信頼しますか?" - -#: notebook/static/notebook/js/notebook.js:2981 -msgid "Notebook failed to load" -msgstr "ノートブックの読み込みに失敗しました" - -#: notebook/static/notebook/js/notebook.js:2983 -msgid "The error was: " -msgstr "エラー: " - -#: notebook/static/notebook/js/notebook.js:2987 -msgid "See the error console for details." -msgstr "詳しくはエラーコンソールを参照して下さい。" - -#: notebook/static/notebook/js/notebook.js:2995 -msgid "The notebook also failed validation:" -msgstr "ノートブックの検証に失敗しました:" - -#: notebook/static/notebook/js/notebook.js:2997 -msgid "An invalid notebook may not function properly. The validation error was:" -msgstr "無効なノートブックは正しく機能しない可能性があります。検証エラーは次の通りです:" - -#: notebook/static/notebook/js/notebook.js:3036 -#, python-format -msgid "This notebook has been converted from an older notebook format to the current notebook format v(%s)." -msgstr "このノートブックは古いノートブックの形式から現在の形式 v(%s) に変換されました。" - -#: notebook/static/notebook/js/notebook.js:3038 -#, python-format -msgid "This notebook has been converted from a newer notebook format to the current notebook format v(%s)." -msgstr "このノートブックは新しいノートブックの形式から現在の形式 v(%s) に変換されました。" - -#: notebook/static/notebook/js/notebook.js:3046 -msgid "The next time you save this notebook, the current notebook format will be used." -msgstr "次回このノートブックを保存する時は現在のノートブックの形式が使用されます。" - -#: notebook/static/notebook/js/notebook.js:3051 -msgid "Older versions of Jupyter may not be able to read the new format." -msgstr "古いバージョンの Jupyter は新しい形式を読むことができない場合があります。" - -#: notebook/static/notebook/js/notebook.js:3053 -msgid "Some features of the original notebook may not be available." -msgstr "オリジナルのノートブックの中には利用できない機能が幾つかあります。" - -#: notebook/static/notebook/js/notebook.js:3056 -msgid "To preserve the original version, close the notebook without saving it." -msgstr "元のバージョンを残すには保存せずにノートブックを閉じます" - -#: notebook/static/notebook/js/notebook.js:3061 -msgid "Notebook converted" -msgstr "ノートブックは変換されました" - -#: notebook/static/notebook/js/notebook.js:3083 -msgid "(No name)" -msgstr "(無題)" - -#: notebook/static/notebook/js/notebook.js:3131 -#, python-format -msgid "An unknown error occurred while loading this notebook. This version can load notebook formats %s or earlier. See the server log for details." -msgstr "このノートブックの読み込み中に不明なエラーが発生しました。このバージョンはノートブックの形式 %s とそれ以前のバージョンをロードできます。 詳細についてはサーバのログを参照して下さい。" - -#: notebook/static/notebook/js/notebook.js:3142 -msgid "Error loading notebook" -msgstr "ノートブックの読み込み中にエラー" - -#: notebook/static/notebook/js/notebook.js:3243 -msgid "Are you sure you want to revert the notebook to the latest checkpoint?" -msgstr "本当に最終チェックポイントへノートブックを復元しますか?" - -#: notebook/static/notebook/js/notebook.js:3246 -msgid "This cannot be undone." -msgstr "この操作は取り消せません。" - -#: notebook/static/notebook/js/notebook.js:3249 -msgid "The checkpoint was last updated at:" -msgstr "チェックポイントはこの時間に変更されました:" - -#: notebook/static/notebook/js/notebook.js:3260 -msgid "Revert notebook to checkpoint" -msgstr "ノートブックをチェックポイントへ復元" - -#: notebook/static/notebook/js/notificationarea.js:77 -#: notebook/static/notebook/js/tour.js:61 -#: notebook/static/notebook/js/tour.js:67 -msgid "Edit Mode" -msgstr "編集モード" - -#: notebook/static/notebook/js/notificationarea.js:84 -#: notebook/static/notebook/js/notificationarea.js:88 -#: notebook/static/notebook/js/tour.js:54 -msgid "Command Mode" -msgstr "コマンドモード" - -#: notebook/static/notebook/js/notificationarea.js:95 -msgid "Kernel Created" -msgstr "カーネルが作成されました" - -#: notebook/static/notebook/js/notificationarea.js:99 -msgid "Connecting to kernel" -msgstr "カーネルに接続中" - -#: notebook/static/notebook/js/notificationarea.js:103 -msgid "Not Connected" -msgstr "接続されていません" - -#: notebook/static/notebook/js/notificationarea.js:106 -msgid "click to reconnect" -msgstr "クリックして再接続" - -#: notebook/static/notebook/js/notificationarea.js:115 -msgid "Restarting kernel" -msgstr "カーネルを再起動中" - -#: notebook/static/notebook/js/notificationarea.js:129 -msgid "Kernel Restarting" -msgstr "カーネルは再起動中です" - -#: notebook/static/notebook/js/notificationarea.js:130 -msgid "The kernel appears to have died. It will restart automatically." -msgstr "カーネルが異常終了した様です。自動的に再起動します。" - -#: notebook/static/notebook/js/notificationarea.js:140 -#: notebook/static/notebook/js/notificationarea.js:198 -#: notebook/static/notebook/js/notificationarea.js:218 -msgid "Dead kernel" -msgstr "カーネルが異常終了!" - -#: notebook/static/notebook/js/notificationarea.js:141 -#: notebook/static/notebook/js/notificationarea.js:219 -#: notebook/static/notebook/js/notificationarea.js:266 -msgid "Kernel Dead" -msgstr "カーネルが異常終了" - -#: notebook/static/notebook/js/notificationarea.js:145 -msgid "Interrupting kernel" -msgstr "カーネルを中断します!" - -#: notebook/static/notebook/js/notificationarea.js:151 -msgid "No Connection to Kernel" -msgstr "カーネルへの接続がありません" - -#: notebook/static/notebook/js/notificationarea.js:161 -msgid "A connection to the notebook server could not be established. The notebook will continue trying to reconnect. Check your network connection or notebook server configuration." -msgstr "ノートブックサーバへの接続を確立できませんでした。ノートブックは再接続を試みます。ネットワーク接続またはノートブックサーバの設定を確認してください。" - -#: notebook/static/notebook/js/notificationarea.js:166 -msgid "Connection failed" -msgstr "接続に失敗しました" - -#: notebook/static/notebook/js/notificationarea.js:179 -msgid "No kernel" -msgstr "カーネルが見つかりません" - -#: notebook/static/notebook/js/notificationarea.js:180 -msgid "Kernel is not running" -msgstr "カーネルは起動していません" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Don't Restart" -msgstr "再起動しない" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Try Restarting Now" -msgstr "再起動を試みます" - -#: notebook/static/notebook/js/notificationarea.js:191 -msgid "The kernel has died, and the automatic restart has failed. It is possible the kernel cannot be restarted. If you are not able to restart the kernel, you will still be able to save the notebook, but running code will no longer work until the notebook is reopened." -msgstr "カーネルが異常終了し自動再起動が失敗しました。カーネルを再起動できない可能性があります。カーネルを再起動できない場合でもノートブックを保存することはできますがコードの実行はノートブックを開き直すまで機能しなくなります。" - -#: notebook/static/notebook/js/notificationarea.js:225 -msgid "No Kernel" -msgstr "カーネルが見つかりません" - -#: notebook/static/notebook/js/notificationarea.js:252 -msgid "Failed to start the kernel" -msgstr "カーネルの起動に失敗しました" - -#: notebook/static/notebook/js/notificationarea.js:272 -#: notebook/static/notebook/js/notificationarea.js:292 -#: notebook/static/notebook/js/notificationarea.js:306 -msgid "Kernel Busy" -msgstr "カーネルがビジー" - -#: notebook/static/notebook/js/notificationarea.js:273 -msgid "Kernel starting, please wait..." -msgstr "カーネルを起動しています。お待ちください..." - -#: notebook/static/notebook/js/notificationarea.js:279 -#: notebook/static/notebook/js/notificationarea.js:286 -msgid "Kernel Idle" -msgstr "カーネルは休止状態" - -#: notebook/static/notebook/js/notificationarea.js:280 -msgid "Kernel ready" -msgstr "カーネルの準備が完了" - -#: notebook/static/notebook/js/notificationarea.js:297 -msgid "Using kernel: " -msgstr "カーネルを使用しています: " - -#: notebook/static/notebook/js/notificationarea.js:298 -msgid "Only candidate for language: %1$s was %2$s." -msgstr "唯一の言語の候補: %1$s は %2$s." - -#: notebook/static/notebook/js/notificationarea.js:319 -msgid "Loading notebook" -msgstr "ノートブックを読み込んでいます" - -#: notebook/static/notebook/js/notificationarea.js:322 -msgid "Notebook loaded" -msgstr "ノートブックが読み込まれました" - -#: notebook/static/notebook/js/notificationarea.js:325 -msgid "Saving notebook" -msgstr "ノートブックを保存しています" - -#: notebook/static/notebook/js/notificationarea.js:328 -msgid "Notebook saved" -msgstr "ノートブックが保存されました" - -#: notebook/static/notebook/js/notificationarea.js:331 -msgid "Notebook save failed" -msgstr "ノートブックの保存に失敗しました" - -#: notebook/static/notebook/js/notificationarea.js:334 -msgid "Notebook copy failed" -msgstr "ノートブックのコピーに失敗しました" - -#: notebook/static/notebook/js/notificationarea.js:339 -msgid "Checkpoint created" -msgstr "チェックポイントが作成されました" - -#: notebook/static/notebook/js/notificationarea.js:347 -msgid "Checkpoint failed" -msgstr "チェックポイントの失敗" - -#: notebook/static/notebook/js/notificationarea.js:350 -msgid "Checkpoint deleted" -msgstr "チェックポイントの削除" - -#: notebook/static/notebook/js/notificationarea.js:353 -msgid "Checkpoint delete failed" -msgstr "チェックポイントの削除に失敗しました" - -#: notebook/static/notebook/js/notificationarea.js:356 -msgid "Restoring to checkpoint..." -msgstr "チェックポイントの復元..." - -#: notebook/static/notebook/js/notificationarea.js:359 -msgid "Checkpoint restore failed" -msgstr "チェックポイントの復元に失敗しました" - -#: notebook/static/notebook/js/notificationarea.js:364 -msgid "Autosave disabled" -msgstr "自動保存は無効" - -#: notebook/static/notebook/js/notificationarea.js:367 -#, python-format -msgid "Saving every %d sec." -msgstr "%d 秒で保存" - -#: notebook/static/notebook/js/notificationarea.js:383 -msgid "Trusted" -msgstr "信頼済み" - -#: notebook/static/notebook/js/notificationarea.js:385 -msgid "Not Trusted" -msgstr "信頼されていません" - -#: notebook/static/notebook/js/outputarea.js:75 -msgid "click to expand output" -msgstr "出力を広げるにはクリックします" - -#: notebook/static/notebook/js/outputarea.js:79 -msgid "click to expand output; double click to hide output" -msgstr "出力を広げるにはクリックします; ダブルクリックで非表示" - -#: notebook/static/notebook/js/outputarea.js:167 -msgid "click to unscroll output; double click to hide" -msgstr "出力のスクロールを止めるためにクリック; ダブルクリックで非表示" - -#: notebook/static/notebook/js/outputarea.js:174 -msgid "click to scroll output; double click to hide" -msgstr "出力をスクロールするためにクリック; ダブルクリックで非表示" - -#: notebook/static/notebook/js/outputarea.js:422 -msgid "Javascript error adding output!" -msgstr "Javascript エラーが出力に追加されました!" - -#: notebook/static/notebook/js/outputarea.js:427 -msgid "See your browser Javascript console for more details." -msgstr "より詳細を知るにはブラウザの Javascript コンソールを確認して下さい。" - -#: notebook/static/notebook/js/outputarea.js:468 -#, python-format -msgid "Out[%s]:" -msgstr "出力[%s]:" - -#: notebook/static/notebook/js/outputarea.js:577 -#, python-format -msgid "Unrecognized output: %s" -msgstr "認識できない出力: %s" - -#: notebook/static/notebook/js/pager.js:36 -msgid "Open the pager in an external window" -msgstr "外部ウィンドウでページャを開く" - -#: notebook/static/notebook/js/pager.js:45 -msgid "Close the pager" -msgstr "ページャを閉じる" - -#: notebook/static/notebook/js/pager.js:148 -msgid "Jupyter Pager" -msgstr "Jupyter ページャ" - -#: notebook/static/notebook/js/quickhelp.js:39 -#: notebook/static/notebook/js/quickhelp.js:49 -#: notebook/static/notebook/js/quickhelp.js:50 -msgid "go to cell start" -msgstr "セルの先頭に移動" - -#: notebook/static/notebook/js/quickhelp.js:40 -#: notebook/static/notebook/js/quickhelp.js:51 -#: notebook/static/notebook/js/quickhelp.js:52 -msgid "go to cell end" -msgstr "セルの末尾に移動" - -#: notebook/static/notebook/js/quickhelp.js:41 -#: notebook/static/notebook/js/quickhelp.js:53 -msgid "go one word left" -msgstr "単語1つ左に移動" - -#: notebook/static/notebook/js/quickhelp.js:42 -#: notebook/static/notebook/js/quickhelp.js:54 -msgid "go one word right" -msgstr "単語1つ右に移動" - -#: notebook/static/notebook/js/quickhelp.js:43 -#: notebook/static/notebook/js/quickhelp.js:55 -msgid "delete word before" -msgstr "前の単語を削除" - -#: notebook/static/notebook/js/quickhelp.js:44 -#: notebook/static/notebook/js/quickhelp.js:56 -msgid "delete word after" -msgstr "続く単語を削除" - -#: notebook/static/notebook/js/quickhelp.js:61 -msgid "code completion or indent" -msgstr "コード補完またはインデント" - -#: notebook/static/notebook/js/quickhelp.js:62 -msgid "tooltip" -msgstr "ツールチップ" - -#: notebook/static/notebook/js/quickhelp.js:63 -msgid "indent" -msgstr "インデント" - -#: notebook/static/notebook/js/quickhelp.js:64 -msgid "dedent" -msgstr "インデント解除" - -#: notebook/static/notebook/js/quickhelp.js:65 -msgid "select all" -msgstr "全てを選択" - -#: notebook/static/notebook/js/quickhelp.js:66 -msgid "undo" -msgstr "元に戻す" - -#: notebook/static/notebook/js/quickhelp.js:67 -#: notebook/static/notebook/js/quickhelp.js:68 -msgid "redo" -msgstr "やり直し" - -#: notebook/static/notebook/js/quickhelp.js:102 -#: notebook/static/notebook/js/quickhelp.js:243 -msgid "Shift" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:103 -msgid "Alt" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:104 -msgid "Up" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:105 -msgid "Down" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:106 -msgid "Left" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:107 -msgid "Right" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:108 -#: notebook/static/notebook/js/quickhelp.js:246 -msgid "Tab" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:109 -msgid "Caps Lock" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:110 -#: notebook/static/notebook/js/quickhelp.js:269 -msgid "Esc" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:111 -msgid "Ctrl" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:112 -#: notebook/static/notebook/js/quickhelp.js:290 -msgid "Enter" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:113 -msgid "Page Up" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:114 -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "Page Down" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:115 -msgid "Home" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:116 -msgid "End" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:117 -#: notebook/static/notebook/js/quickhelp.js:245 -msgid "Space" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:118 -msgid "Backspace" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:119 -msgid "Minus" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "PageUp" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:197 -msgid "The Jupyter Notebook has two different keyboard input modes." -msgstr "Jupyter Notebook は異なる2つのキーボード入力モードを持っています。" - -#: notebook/static/notebook/js/quickhelp.js:199 -msgid "Edit mode allows you to type code or text into a cell and is indicated by a green cell border." -msgstr "編集モード は緑色のセル枠で表示され、セルにコードまたはテキストを入力できます。" - -#: notebook/static/notebook/js/quickhelp.js:201 -msgid "Command mode binds the keyboard to notebook level commands and is indicated by a grey cell border with a blue left margin." -msgstr "コマンドモード は青い左マージンを持つ灰色のセル枠で表示され、ノートブックレベルのコマンドにキーボードをバインドします。" - -#: notebook/static/notebook/js/quickhelp.js:222 -#: notebook/static/notebook/js/tooltip.js:58 -#: notebook/static/notebook/js/tooltip.js:69 -msgid "Close" -msgstr "閉じる" - -#: notebook/static/notebook/js/quickhelp.js:225 -msgid "Keyboard shortcuts" -msgstr "キーボードショートカット" - -#: notebook/static/notebook/js/quickhelp.js:240 -msgid "Command" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:241 -msgid "Control" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:242 -msgid "Option" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:244 -msgid "Return" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:270 -#, python-format -msgid "Command Mode (press %s to enable)" -msgstr "コマンドモード (有効にするには %s を押下)" - -#: notebook/static/notebook/js/quickhelp.js:272 -msgid "Edit Shortcuts" -msgstr "ショートカットを編集" - -#: notebook/static/notebook/js/quickhelp.js:275 -msgid "edit command-mode keyboard shortcuts" -msgstr "コマンドモードのキーボードショートカットを編集" - -#: notebook/static/notebook/js/quickhelp.js:292 -#, python-format -msgid "Edit Mode (press %s to enable)" -msgstr "編集モード (有効にするには %s を押下)" - -#: notebook/static/notebook/js/savewidget.js:49 -msgid "Autosave Failed!" -msgstr "自動保存に失敗!" - -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:846 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Rename" -msgstr "リネーム" - -#: notebook/static/notebook/js/savewidget.js:78 -#: notebook/static/tree/js/notebooklist.js:837 -msgid "Enter a new notebook name:" -msgstr "新しいノートブックの名前を入力:" - -#: notebook/static/notebook/js/savewidget.js:86 -msgid "Rename Notebook" -msgstr "ノートブックのリネーム" - -#: notebook/static/notebook/js/savewidget.js:98 -msgid "Invalid notebook name. Notebook names must have 1 or more characters and can contain any characters except :/\\. Please enter a new notebook name:" -msgstr "不正なノートブックの名前です。ノートブックの名前は :/\\ を除く1文字以上でなければなりません。新しいノートブックの名前を入力して下さい:" - -#: notebook/static/notebook/js/savewidget.js:103 -msgid "Renaming..." -msgstr "リネーム中..." - -#: notebook/static/notebook/js/savewidget.js:109 -msgid "Unknown error" -msgstr "不明なエラー" - -#: notebook/static/notebook/js/savewidget.js:178 -msgid "no checkpoint" -msgstr "チェックポイントはありません" - -#: notebook/static/notebook/js/savewidget.js:193 -#, python-format -msgid "Last Checkpoint: %s" -msgstr "最終チェックポイント: %s" - -#: notebook/static/notebook/js/savewidget.js:217 -msgid "(unsaved changes)" -msgstr "(未保存の変更)" - -#: notebook/static/notebook/js/savewidget.js:219 -msgid "(autosaved)" -msgstr "(自動保存)" - -#: notebook/static/notebook/js/searchandreplace.js:74 -#, python-format -msgid "Warning: too many matches (%d). Some changes might not be shown or applied." -msgstr "警告: マッチが多すぎます (%d 個)。幾らかの変更は表示または適用されません。" - -#: notebook/static/notebook/js/searchandreplace.js:77 -#, python-format -msgid "%d match" -msgid_plural "%d matches" -msgstr[0] "%d 個にマッチ" -msgstr[1] "%d 個にマッチ" - -#: notebook/static/notebook/js/searchandreplace.js:145 -msgid "More than 100 matches, aborting" -msgstr "100 個以上にマッチしたため中断します" - -#: notebook/static/notebook/js/searchandreplace.js:166 -msgid "Use regex (JavaScript regex syntax)" -msgstr "正規表現の使用 (JavaScript 正規表現)" - -#: notebook/static/notebook/js/searchandreplace.js:174 -msgid "Replace in selected cells" -msgstr "選択中のセルを入れ替え" - -#: notebook/static/notebook/js/searchandreplace.js:181 -msgid "Match case" -msgstr "大文字と小文字の両方にマッチ" - -#: notebook/static/notebook/js/searchandreplace.js:187 -msgid "Find" -msgstr "検索" - -#: notebook/static/notebook/js/searchandreplace.js:203 -msgid "Replace" -msgstr "置換" - -#: notebook/static/notebook/js/searchandreplace.js:255 -msgid "No matches, invalid or empty regular expression" -msgstr "マッチしません。不正または空の正規表現です" - -#: notebook/static/notebook/js/searchandreplace.js:370 -msgid "Replace All" -msgstr "全て置換" - -#: notebook/static/notebook/js/searchandreplace.js:374 -msgid "Find and Replace" -msgstr "検索と置換" - -#: notebook/static/notebook/js/searchandreplace.js:400 -#: notebook/static/notebook/js/searchandreplace.js:401 -msgid "find and replace" -msgstr "検索と置換" - -#: notebook/static/notebook/js/textcell.js:551 -msgid "Write raw LaTeX or other formats here, for use with nbconvert. It will not be rendered in the notebook. When passing through nbconvert, a Raw Cell's content is added to the output unmodified." -msgstr "nbconvert で使うために生の LaTeX や他の形式をここに書いてください。これらはノートブックには表示されません。nbconvert に渡されると Raw Cell の内容が変更されずに出力に追加されます。" - -#: notebook/static/notebook/js/tooltip.js:41 -msgid "Grow the tooltip vertically (press shift-tab twice)" -msgstr "ツールチップを垂直方向に広げる(shift-tabを2回押す)" - -#: notebook/static/notebook/js/tooltip.js:48 -msgid "show the current docstring in pager (press shift-tab 4 times)" -msgstr "現在の docstring をページャで表示します(shift-tabを4回押します)" - -#: notebook/static/notebook/js/tooltip.js:49 -msgid "Open in Pager" -msgstr "ページャで開く" - -#: notebook/static/notebook/js/tooltip.js:68 -msgid "Tooltip will linger for 10 seconds while you type" -msgstr "ツールチップは入力中の 10 秒間表示されます" - -#: notebook/static/notebook/js/tour.js:27 -msgid "Welcome to the Notebook Tour" -msgstr "ノートブックツアーへようこそ" - -#: notebook/static/notebook/js/tour.js:30 -msgid "You can use the left and right arrow keys to go backwards and forwards." -msgstr "先に進んだり前に戻るにはカーソルの左と右を使う事ができます。" - -#: notebook/static/notebook/js/tour.js:33 -msgid "Filename" -msgstr "ファイル名" - -#: notebook/static/notebook/js/tour.js:35 -msgid "Click here to change the filename for this notebook." -msgstr "このノートブックのファイル名を変更するにはここをクリックします。" - -#: notebook/static/notebook/js/tour.js:39 -msgid "Notebook Menubar" -msgstr "ノートブックメニューバー" - -#: notebook/static/notebook/js/tour.js:40 -msgid "The menubar has menus for actions on the notebook, its cells, and the kernel it communicates with." -msgstr "メニューバーにはノートブック、そのセル、およびそれらが通信するカーネルに対するアクションのためのメニューがあります。" - -#: notebook/static/notebook/js/tour.js:44 -msgid "Notebook Toolbar" -msgstr "ノートブックツールバー" - -#: notebook/static/notebook/js/tour.js:45 -msgid "The toolbar has buttons for the most common actions. Hover your mouse over each button for more information." -msgstr "ツールバーには最も一般的な操作のボタンが置かれます。 詳細については各ボタンの上にマウスを移動してください。" - -#: notebook/static/notebook/js/tour.js:48 -msgid "Mode Indicator" -msgstr "モードインジケータ" - -#: notebook/static/notebook/js/tour.js:50 -msgid "The Notebook has two modes: Edit Mode and Command Mode. In this area, an indicator can appear to tell you which mode you are in." -msgstr "ノートブックには編集モードとコマンドモードの2つのモードがあります。この領域にはどのモードにいるのかを示すインジケータが表示されます。" - -#: notebook/static/notebook/js/tour.js:58 -msgid "Right now you are in Command Mode, and many keyboard shortcuts are available. In this mode, no icon is displayed in the indicator area." -msgstr "現在あなたはコマンドモードにいるので多くのキーボードショートカットが利用可能です。 このモードではインジケータ領域にアイコンは表示されません。" - -#: notebook/static/notebook/js/tour.js:64 -msgid "Pressing Enter or clicking in the input text area of the cell switches to Edit Mode." -msgstr "Enterを押下、セルのテキストの入力エリアをクリックすると編集モードに切り替わります。" - -#: notebook/static/notebook/js/tour.js:70 -msgid "Notice that the border around the currently active cell changed color. Typing will insert text into the currently active cell." -msgstr "現在アクティブなセルの周囲の境界線の色が変わることに注目してください。文字を入力すると現在アクティブなセルにテキストが挿入されます。" - -#: notebook/static/notebook/js/tour.js:73 -msgid "Back to Command Mode" -msgstr "コマンドモードに戻る" - -#: notebook/static/notebook/js/tour.js:76 -msgid "Pressing Esc or clicking outside of the input text area takes you back to Command Mode." -msgstr "Escを押下、またはテキストの入力エリアの外側をクリックするとコマンドモードに戻ります。" - -#: notebook/static/notebook/js/tour.js:79 -msgid "Keyboard Shortcuts" -msgstr "キーボードショートカット" - -#: notebook/static/notebook/js/tour.js:91 -msgid "You can click here to get a list of all of the keyboard shortcuts." -msgstr "ここをクリックすると全てのキーボードショートカットの一覧が表示されます。" - -#: notebook/static/notebook/js/tour.js:94 -#: notebook/static/notebook/js/tour.js:100 -msgid "Kernel Indicator" -msgstr "カーネルインジケータ" - -#: notebook/static/notebook/js/tour.js:97 -msgid "This is the Kernel indicator. It looks like this when the Kernel is idle." -msgstr "これはカーネルインジケータです。カーネルがアイドル状態のときはこの様に表示されます。" - -#: notebook/static/notebook/js/tour.js:103 -msgid "The Kernel indicator looks like this when the Kernel is busy." -msgstr "カーネルインジケータはカーネルがビジーのときはこのように表示されます。" - -#: notebook/static/notebook/js/tour.js:107 -msgid "Interrupting the Kernel" -msgstr "カーネルの中断" - -#: notebook/static/notebook/js/tour.js:109 -msgid "To cancel a computation in progress, you can click here." -msgstr "実行中の計算をキャンセルするにはここをクリックして下さい。" - -#: notebook/static/notebook/js/tour.js:114 -msgid "Notification Area" -msgstr "通知エリア" - -#: notebook/static/notebook/js/tour.js:115 -msgid "Messages in response to user actions (Save, Interrupt, etc.) appear here." -msgstr "ユーザーアクション (保存、割り込みなど) に応じたメッセージがここに表示されます。" - -#: notebook/static/notebook/js/tour.js:117 -msgid "End of Tour" -msgstr "ツアーの終わり" - -#: notebook/static/notebook/js/tour.js:120 -msgid "This concludes the Jupyter Notebook User Interface Tour." -msgstr "これで Jupyter Notebook のユーザーインタフェースのツアーは終了です。" - -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32 -msgid "Edit Attachments" -msgstr "添付ファイルを編集" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:19 -msgid "Cell" -msgstr "セル" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:29 -#: notebook/static/notebook/js/celltoolbarpresets/default.js:47 -msgid "Edit Metadata" -msgstr "メタデータを編集" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22 -msgid "Custom" -msgstr "カスタム" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32 -msgid "Set the MIME type of the raw cell:" -msgstr "Raw セルの MIME タイプを設定:" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40 -msgid "Raw Cell MIME Type" -msgstr "Raw セル MIME タイプ" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74 -msgid "Raw NBConvert Format" -msgstr "Raw NBConvert 書式" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81 -msgid "Raw Cell Format" -msgstr "Raw セル書式" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15 -msgid "Slide" -msgstr "スライド" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:16 -msgid "Sub-Slide" -msgstr "サブスライド" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:17 -msgid "Fragment" -msgstr "フラグメント" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:18 -msgid "Skip" -msgstr "スキップ" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:19 -msgid "Notes" -msgstr "ノート" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35 -msgid "Slide Type" -msgstr "スライドタイプ" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41 -msgid "Slideshow" -msgstr "スライドショー" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:133 -msgid "Add tag" -msgstr "タグを追加" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163 -msgid "Edit the list of tags below. All whitespace is treated as tag separators." -msgstr "以下のタグ一覧を編集。全ての空白はタグのセパレータとして扱われます。" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172 -msgid "Edit the tags" -msgstr "タグを編集" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186 -msgid "Edit Tags" -msgstr "タグを編集" - -#: notebook/static/tree/js/kernellist.js:86 -#: notebook/static/tree/js/terminallist.js:105 -msgid "Shutdown" -msgstr "シャットダウン" - -#: notebook/static/tree/js/newnotebook.js:70 -#, python-format -msgid "Create a new notebook with %s" -msgstr "新しいノートブック %s を作成" - -#: notebook/static/tree/js/newnotebook.js:101 -msgid "An error occurred while creating a new notebook." -msgstr "新しいノートブックの作成中にエラーが発生しました。" - -#: notebook/static/tree/js/notebooklist.js:122 -msgid "Creating File Failed" -msgstr "ファイルの作成に失敗" - -#: notebook/static/tree/js/notebooklist.js:124 -msgid "An error occurred while creating a new file." -msgstr "新しいファイルの作成中に失敗しました。" - -#: notebook/static/tree/js/notebooklist.js:142 -msgid "Creating Folder Failed" -msgstr "フォルダの作成に失敗" - -#: notebook/static/tree/js/notebooklist.js:144 -msgid "An error occurred while creating a new folder." -msgstr "新しいフォルダの作成中にエラーが発生しました。" - -#: notebook/static/tree/js/notebooklist.js:271 -msgid "Failed to read file" -msgstr "ファイルの読み込みに失敗しました" - -#: notebook/static/tree/js/notebooklist.js:272 -#, python-format -msgid "Failed to read file %s" -msgstr "%s の読み込みに失敗しました" - -#: notebook/static/tree/js/notebooklist.js:283 -#, python-format -msgid "The file size is %d MB. Do you still want to upload it?" -msgstr "ファイルサイズは %d MB です。本当にアップロードしますか?" - -#: notebook/static/tree/js/notebooklist.js:286 -msgid "Large file size warning" -msgstr "大きいファイルサイズの警告" - -#: notebook/static/tree/js/notebooklist.js:355 -msgid "Server error: " -msgstr "サーバエラー:" - -#: notebook/static/tree/js/notebooklist.js:390 -msgid "The notebook list is empty." -msgstr "ノートブック一覧は空です。" - -#: notebook/static/tree/js/notebooklist.js:463 -msgid "Click here to rename, delete, etc." -msgstr "リネーム、削除、その他を実行するにはここをクリック" - -#: notebook/static/tree/js/notebooklist.js:503 -msgid "Running" -msgstr "実行中" - -#: notebook/static/tree/js/notebooklist.js:835 -msgid "Enter a new file name:" -msgstr "新しいファイル名を入力:" - -#: notebook/static/tree/js/notebooklist.js:836 -msgid "Enter a new directory name:" -msgstr "新しいディレクトリ名を入力:" - -#: notebook/static/tree/js/notebooklist.js:838 -msgid "Enter a new name:" -msgstr "新しい名前を入力:" - -#: notebook/static/tree/js/notebooklist.js:843 -msgid "Rename file" -msgstr "ファイルのリネーム" - -#: notebook/static/tree/js/notebooklist.js:844 -msgid "Rename directory" -msgstr "ディレクトリのリネーム" - -#: notebook/static/tree/js/notebooklist.js:845 -msgid "Rename notebook" -msgstr "ノートブックのリネーム" - -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Move" -msgstr "移動" - -#: notebook/static/tree/js/notebooklist.js:875 -msgid "An error occurred while renaming \"%1$s\" to \"%2$s\"." -msgstr "\"%1$s\" を \"%2$s\" にリネーム中にエラーが発生しました。" - -#: notebook/static/tree/js/notebooklist.js:878 -msgid "Rename Failed" -msgstr "リネームの失敗" - -#: notebook/static/tree/js/notebooklist.js:927 -#, python-format -msgid "Enter a new destination directory path for this item:" -msgid_plural "Enter a new destination directory path for these %d items:" -msgstr[0] "このアイテムの移動先を入力して下さい:" -msgstr[1] "%d 個のアイテムの移動先を入力して下さい:" - -#: notebook/static/tree/js/notebooklist.js:940 -#, python-format -msgid "Move an Item" -msgid_plural "Move %d Items" -msgstr[0] "アイテムの移動" -msgstr[1] "%d 個のアイテムの移動" - -#: notebook/static/tree/js/notebooklist.js:959 -msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"." -msgstr "\"%1$s\" を \"%2$s\" から \"%3$s\" に移動する際に失敗しました。" - -#: notebook/static/tree/js/notebooklist.js:961 -msgid "Move Failed" -msgstr "ファイルの移動に失敗" - -#: notebook/static/tree/js/notebooklist.js:1007 -#, python-format -msgid "Are you sure you want to permanently delete: \"%s\"?" -msgid_plural "Are you sure you want to permanently delete the %d files or folders selected?" -msgstr[0] "本当に \"%s\" を完全に削除しますか?" -msgstr[1] "本当に %d 個のファイルまたはディレクトリを完全に削除しますか?" - -#: notebook/static/tree/js/notebooklist.js:1035 -#, python-format -msgid "An error occurred while deleting \"%s\"." -msgstr "\"%s\" を削除中にエラーが発生しました。" - -#: notebook/static/tree/js/notebooklist.js:1037 -msgid "Delete Failed" -msgstr "削除に失敗" - -#: notebook/static/tree/js/notebooklist.js:1078 -#, python-format -msgid "Are you sure you want to duplicate: \"%s\"?" -msgid_plural "Are you sure you want to duplicate the %d files selected?" -msgstr[0] "本当に \"%s\" を複製しますか?" -msgstr[1] "本当に %d 個のファイルを複製しますか?" - -#: notebook/static/tree/js/notebooklist.js:1088 -msgid "Duplicate" -msgstr "複製" - -#: notebook/static/tree/js/notebooklist.js:1102 -#, python-format -msgid "An error occurred while duplicating \"%s\"." -msgstr "\"%s\" の複製中に失敗" - -#: notebook/static/tree/js/notebooklist.js:1104 -msgid "Duplicate Failed" -msgstr "複製に失敗" - -#: notebook/static/tree/js/notebooklist.js:1323 -msgid "Upload" -msgstr "アップロード" - -#: notebook/static/tree/js/notebooklist.js:1332 -msgid "Invalid file name" -msgstr "ファイル名が不正です" - -#: notebook/static/tree/js/notebooklist.js:1333 -msgid "File names must be at least one character and not start with a period" -msgstr "ファイル名はピリオドで始まっていない1文字以上の名前でなければなりません" - -#: notebook/static/tree/js/notebooklist.js:1362 -msgid "Cannot upload invalid Notebook" -msgstr "不正なノートブックのためアップロードできません" - -#: notebook/static/tree/js/notebooklist.js:1395 -#, python-format -msgid "There is already a file named \"%s\". Do you want to replace it?" -msgstr "既に \"%s\" という名前のファイルが存在します。入れ替えますか?" - -#: notebook/static/tree/js/notebooklist.js:1397 -msgid "Replace file" -msgstr "ファイルの入れ替え" diff --git a/notebook/i18n/ja_JP/LC_MESSAGES/nbui.po b/notebook/i18n/ja_JP/LC_MESSAGES/nbui.po deleted file mode 100644 index 128b48026..000000000 --- a/notebook/i18n/ja_JP/LC_MESSAGES/nbui.po +++ /dev/null @@ -1,740 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-07 12:48-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "要求したページは存在しません!" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "現在のモード" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "ファイル" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "新規" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "保存" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "リネーム" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "ダウンロード" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "編集" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "検索" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "検索と置換" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "キーマッピング" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "デフォルト" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "表示" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "ロゴとノートブックのタイトルを表示/非表示 (メニューバーの上)" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "ヘッダをトグル" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "行番号をトグル" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "言語" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "エラー内容:" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "パスワードまたはトークン:" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "パスワード:" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "ログイン" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "ログインしていないのでこのページを見る事はできません。" - -#: notebook/templates/logout.html:24 -#, python-format -msgid "Proceed to the dashboard" -msgstr "ダッシュボード" - -#: notebook/templates/logout.html:26 -#, python-format -msgid "Proceed to the login page" -msgstr "ログインページ" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "メニュー" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "カーネル" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "このノートブックは読み取り専用です" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "新しいノートブック" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "ダッシュボードで新しいウィンドウを開く" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "開く..." - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "このノートブックの内容の複製を開き新しいカーネルを起動する" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "コピーを作る..." - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "リネーム..." - -msgid "Save as..." -msgstr "名前を付けて保存..." - -msgid "Quit" -msgstr "終了" - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "保存とチェックポイント" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "チェックポイントを元に戻す" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "印刷プレビュー" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "名前を付けてダウンロード" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "ノートブック (.ipynb)" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "スクリプト" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "名前を付けてデプロイ" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "このノートブックの出力を信頼する" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "ノートブックを信頼する" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "このノートブックのカーネルをシャットダウンし、このウィンドウを閉じる" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "閉じて終了" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "セルを切り取り" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "セルをコピー" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "上にセルをペースト" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "下にセルをペースト" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "セルをペーストして入れ替え(&A)" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "セルを削除" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "セルの削除を取り消し" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "セルを分割" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "上のセルをマージ" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "下のセルをマージ" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "セルを上に移動" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "セルを下に移動" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "ノートブックのメタデータを編集" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "検索と置換" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "セルのアタッチメントを切り取り" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "セルのアタッチメントをコピー" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "セルのアタッチメントをペースト" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "画像を挿入" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "アクションアイコンを表示/非表示 (メニューバーの下)" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "ツールバーをトグル" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "セル内の行番号を表示/非表示" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "セルツールバー" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "挿入" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "現在アクティブなセルの上に空のコードセルを挿入する" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "上にセルを挿入" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "現在アクティブなセルの下に空のコードセルを挿入する" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "下にセルを挿入" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "セル" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "このセルを実行しカーソルを一つ次に移動する" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "セルを実行" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "このセルを実行し下を選択する" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "ここまでのセルを実行し下を選択する" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "このセルを実行し下に挿入" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "ここまでのセルを実行し下に挿入" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "ノートブックの全てのセルを実行" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "全てを実行" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "このセルの上にある (このセルは含まない) すべてのセルを実行する" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "ここまでのセルの全てを実行" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "このセルと以下のすべてのセルを実行" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "以下を全て実行" - -#: notebook/templates/notebook.html:205 -msgid "All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells" -msgstr "ノートブック上のすべてのセルには種別があります。デフォルトでは新しいセルは 'コード' セルとして作成されます" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "セルの種別" - -#: notebook/templates/notebook.html:209 -msgid "Contents will be sent to the kernel for execution, and output will display in the footer of cell" -msgstr "実行のために内容がカーネルに送られ、セルのフッターに出力が表示されます" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "内容は HTML としてレンダリングされ説明のテキストとしてサーブされます" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "内容は変更されずに nbconvert に渡されます" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "現在の出力" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "現在のセルの出力を表示/非表示" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "トグル" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "現在のセルの出力をスクロール" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "スクロールをトグル" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "現在のセルの出力をクリア" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "クリア" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "全ての出力" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "全てのセルの出力を表示/非表示" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "全てのセルの出力をスクロール" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "全てのセルの出力をクリア" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "キーボードの中断(CTRL-C)をカーネルに送る" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "中断" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "カーネルを再起動" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "再起動" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "カーネルを再起動し全ての出力をクリアする" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "再起動し出力をクリアする" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "カーネルを再起動しノートブックを再実行する" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "再起動し全てを実行" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "カーネルに再接続する" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "再接続" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "カーネルの変更" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "ヘルプ" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "ノートブックユーザーインターフェースのクイックツアー" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "ユーザーインタフェースツアー" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "全てのキーボードショートカットのツールチップを表示する" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "キーボードショートカット" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "キーボードショートカットの編集ダイアログを開く" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "キーボードショートカットの編集" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "ノートブックのヘルプ" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "新しいウィンドウで開く" - -#: notebook/templates/notebook.html:319 -msgid "About Jupyter Notebook" -msgstr "Jupyter Notebook について" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "詳細" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "Jupyter Notebook には JavaScript が必要です。" - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "続行するには有効にして下さい。 " - -#: notebook/templates/page.html:121 -msgid "dashboard" -msgstr "ダッシュボード" - -#: notebook/templates/page.html:132 -msgid "Logout" -msgstr "ログアウト" - -#: notebook/templates/page.html:134 -msgid "Login" -msgstr "ログイン" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "ファイル" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "実行中" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "クラスタ" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "アクションを実行する為のアイテムを選択して下さい。" - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "選択アイテムを複製する" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "複製" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "選択アイテムをリネームする" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "選択アイテムを移動する" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "移動" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "選択アイテムをダウンロードする" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "選択されているノートブックをシャットダウンする" - -#: notebook/templates/notebook.html:278 -#: notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "シャットダウン" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "選択されているアイテムを表示する" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "選択されているアイテムを編集する" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "選択されているアイテムを削除する" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "クリックしてアップロードするファイルを選択して下さい。" - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "アップロード" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "テキストファイル" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "フォルダ" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "端末" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "端末が存在しません" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "ノートブックの一覧を再読み込み" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "全てを選択 / 解除" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "選択..." - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "全てのフォルダを選択..." - -#: notebook/templates/tree.html:98 -msgid "Folders" -msgstr "フォルダ" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "全てのノートブックを選択" - -#: notebook/templates/tree.html:99 -msgid "All Notebooks" -msgstr "全てのノートブック" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "実行中のノートブックを選択" - -#: notebook/templates/tree.html:100 -msgid "Running" -msgstr "実行中" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "全てのファイルを選択" - -#: notebook/templates/tree.html:101 -msgid "Files" -msgstr "ファイル" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "最終変更時刻" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "名前" - -msgid "File size" -msgstr "ファイルサイズ" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "現在実行中の Jupyter プロセス一覧" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "実行中の一覧を再読み込み" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "実行中の端末はありません。" - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "端末はありません。" - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "ノートブック" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "実行中のノートブックはありません。" - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "Clousters タブが IPython parallel によって提供される様になりました。" - -#: notebook/templates/tree.html:179 -msgid "See 'IPython parallel' for installation details." -msgstr "詳しいインストール方法は 'IPython parallel' を参照" diff --git a/notebook/i18n/ja_JP/LC_MESSAGES/notebook.po b/notebook/i18n/ja_JP/LC_MESSAGES/notebook.po deleted file mode 100644 index f8a68cc95..000000000 --- a/notebook/i18n/ja_JP/LC_MESSAGES/notebook.po +++ /dev/null @@ -1,527 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-08 21:52-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/notebookapp.py:53 -msgid "The Jupyter Notebook requires tornado >= 4.0" -msgstr "Jupyter Notebook は tornade 4.0 以上が必要です" - -#: notebook/notebookapp.py:57 -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "Jupyter Notebook は tornade 4.0 以上が必要ですが 1.1.0 以下です" - -#: notebook/notebookapp.py:59 -#, python-format -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have %s" -msgstr "Jupyter Notebook は tornade 4.0 以上が必要ですが %s です" - -#: notebook/notebookapp.py:209 -msgid "The `ignore_minified_js` flag is deprecated and no longer works." -msgstr "`ignore_minified_js` フラグは非推奨であり既に動作していません。" - -#: notebook/notebookapp.py:210 -#, python-format -msgid "Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "ノートブックの Javascript と LESS で動作する場合には代わりに `%s` を使用してください。" - -#: notebook/notebookapp.py:211 -msgid "The `ignore_minified_js` flag is deprecated and will be removed in Notebook 6.0" -msgstr "`ignore_minified_js` フラグは非推奨でありノートブック 6.0 では削除されます" - -#: notebook/notebookapp.py:389 -msgid "List currently running notebook servers." -msgstr "現在起動中のノートブックサーバの一覧" - -#: notebook/notebookapp.py:393 -msgid "Produce machine-readable JSON output." -msgstr "機械で読み込み可能な JSON 出力。" - -#: notebook/notebookapp.py:397 -msgid "If True, each line of output will be a JSON object with the details from the server info file." -msgstr "True の場合、出力の各行はサーバ情報ファイルからの詳細情報を含む JSON オブジェクトになります。" - -#: notebook/notebookapp.py:402 -msgid "Currently running servers:" -msgstr "現在実行中のサーバ:" - -#: notebook/notebookapp.py:419 -msgid "Don't open the notebook in a browser after startup." -msgstr "起動後にブラウザでノートブックを開かない。" - -#: notebook/notebookapp.py:423 -msgid "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "無効: matplotlib を有効にするにはノートブックで %pylab または %matplotlib を使用して下さい。" - -#: notebook/notebookapp.py:439 -msgid "Allow the notebook to be run from root user." -msgstr "ノートブックをrootユーザーから実行できるようにする。" - -#: notebook/notebookapp.py:470 -msgid "" -"The Jupyter HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client." -msgstr "" -"The Jupyter HTML Notebook.\n" -" \n" -" HTML5/Javascript Notebook クライアントを提供する Tornado ベースの HTML Notebook サーバを起動します。" - -#: notebook/notebookapp.py:509 -msgid "Deprecated: Use minified JS file or not, mainly use during dev to avoid JS recompilation" -msgstr "非推奨: 圧縮された JS ファイルを使用するかどうか。主に開発中に JS が再コンパイルされるのを回避するために使用します。" - -#: notebook/notebookapp.py:540 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "Access-Control-Allow-Credentials: true ヘッダーを設定します。" - -#: notebook/notebookapp.py:544 -msgid "Whether to allow the user to run the notebook as root." -msgstr "ユーザーがノートブックを root として実行できるようにするかどうか。" - -#: notebook/notebookapp.py:548 -msgid "The default URL to redirect to from `/`" -msgstr "`/` からリダイレクトされるデフォルトの URL" - -#: notebook/notebookapp.py:552 -msgid "The IP address the notebook server will listen on." -msgstr "ノートブックサーバが待ち受ける IP アドレス。" - -#: notebook/notebookapp.py:565 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "" -"localhost でバインドできません。デフォルト IP アドレスとして 127.0.0.1 を使用します\n" -"%s" - -#: notebook/notebookapp.py:579 -msgid "The port the notebook server will listen on." -msgstr "ノートブックサーバが待ち受けするポート番号。" - -#: notebook/notebookapp.py:583 -msgid "The number of additional ports to try if the specified port is not available." -msgstr "指定されたポートが利用できない場合に試す追加のポートの数。" - -#: notebook/notebookapp.py:587 -msgid "The full path to an SSL/TLS certificate file." -msgstr "SSL/TLS 証明書ファイルへの完全なパス。" - -#: notebook/notebookapp.py:591 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "SSL/TLS で使用する秘密鍵ファイルへの完全なパス。" - -#: notebook/notebookapp.py:595 -msgid "The full path to a certificate authority certificate for SSL/TLS client authentication." -msgstr "SSL/TLS クライアント認証用の認証局証明書への完全なパス。" - -#: notebook/notebookapp.py:599 -msgid "The file where the cookie secret is stored." -msgstr "cookie secret を保存するファイル。" - -#: notebook/notebookapp.py:628 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "ノートブックサーバは cookie secret を %s に書き込みます" - -#: notebook/notebookapp.py:635 -#, python-format -msgid "Could not set permissions on %s" -msgstr "%s の権限を設定出来ませんでした" - -#: notebook/notebookapp.py:640 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "" -"サーバに接続する際に初回の認証に使われるトークン。\n" -"\n" -" パスワード無しが有効になっている場合\n" -" デフォルト値はランダムなトークンが新しく生成されます。\n" -"\n" -" 空の文字列に設定すると認証が完全に無効になります。これは推奨されていません。\n" -" " - -#: notebook/notebookapp.py:650 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" -"開いたブラウザが仕様するワンタイムトークン。\n" -" 1度使用されると再度使用する事が出来ません。\n" -" " - -#: notebook/notebookapp.py:726 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" -"起動時にどこでノートブックを開くかを指定します。これは\n" -" 標準ライブラリのメソッド `webbrowser.open` の引数 `new` に渡されます。\n" -" 動作は保証されていませんがブラウザのサポートによって異なります。\n" -" 有効な値:\n" -" 2 新しいタブで開く\n" -" 1 新しいウィンドウで開く\n" -" 0 既にあるウィンドウで開く\n" -" 詳細は `webbrowser.open` のドキュメントを参照。\n" -" " - -#: notebook/notebookapp.py:737 -msgid "DEPRECATED, use tornado_settings" -msgstr "非推奨 tornado_settings の使用" - -#: notebook/notebookapp.py:742 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "" -"\n" -" webapp_settings は非推奨です。tornado_settings を使って下さい。\n" - -#: notebook/notebookapp.py:746 -msgid "Supply overrides for the tornado.web.Application that the Jupyter notebook uses." -msgstr "Jupyterノートブックが使用する tornado.web.Application のオーバーライドを指定します。" - -#: notebook/notebookapp.py:750 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" -"\n" -" tornado の websocket 接続の圧縮オプションを指定します。\n" -"\n" -" この値は :meth:`WebSocketHandler.get_compression_options` から返されます。\n" -" None (default) の場合は圧縮は無効になります。\n" -" 辞書 (空でも良い) の場合は圧縮が有効になります。\n" -"\n" -" 詳細は tornado の WebSocketHandler.get_compression_options のドキュメントを参照。\n" -" " - -#: notebook/notebookapp.py:761 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "terminado のオーバーライドを指定します。現時は \"shell_command \" のみをサポートしています。" - -#: notebook/notebookapp.py:764 -msgid "Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details." -msgstr "`set_secure_cookie` に渡す追加のキーワード引数。詳細は tornado の set_secure_cookie のドキュメントを参照。" - -#: notebook/notebookapp.py:768 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" -"tornado HTTPServer の SSL オプションを指定します。\n" -" 詳しくは tornado のドキュメントを参照。" - -#: notebook/notebookapp.py:772 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "Jinja environment に渡される追加の引数を指定します。" - -#: notebook/notebookapp.py:776 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "jinja テンプレートがレンダリングする際に渡される追加の変数。" - -#: notebook/notebookapp.py:812 -msgid "DEPRECATED use base_url" -msgstr "非推奨 base_url の使用" - -#: notebook/notebookapp.py:816 -msgid "base_project_url is deprecated, use base_url" -msgstr "base_project_url は非推奨です。base_url を使用して下さい。" - -#: notebook/notebookapp.py:832 -msgid "Path to search for custom.js, css" -msgstr "custom.js、CSS を検索するためのパス" - -#: notebook/notebookapp.py:844 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "" -"Jinja テンプレートを探す為の追加パス。\n" -"\n" -" notebook.templates を上書きする為に使う事が出来ます。" - -#: notebook/notebookapp.py:855 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "Javascript ノートブック拡張への追加パス" - -#: notebook/notebookapp.py:900 -#, python-format -msgid "Using MathJax: %s" -msgstr "使用している MathJax: %s" - -#: notebook/notebookapp.py:903 -msgid "The MathJax.js configuration file that is to be used." -msgstr "使用される MathJax.js 設定ファイル。" - -#: notebook/notebookapp.py:908 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "使用する MathJax 設定ファイル: %s" - -#: notebook/notebookapp.py:914 -msgid "The notebook manager class to use." -msgstr "ノートブックマネージャのクラス" - -#: notebook/notebookapp.py:920 -msgid "The kernel manager class to use." -msgstr "カーネルマネージャのクラス" - -#: notebook/notebookapp.py:926 -msgid "The session manager class to use." -msgstr "セッションマネージャのクラス" - -#: notebook/notebookapp.py:932 -msgid "The config manager class to use" -msgstr "設定マネージャのクラス" - -#: notebook/notebookapp.py:953 -msgid "The login handler class to use." -msgstr "ログインのハンドラクラス" - -#: notebook/notebookapp.py:960 -msgid "The logout handler class to use." -msgstr "ログアウトのハンドラクラス" - -#: notebook/notebookapp.py:964 -msgid "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL" -msgstr "X-Scheme/X-Forwarded-Proto および X-Real-Ip/X-Forwarded-For ヘッダーがアップストリームのリバースプロキシによって送信されたことを信頼するかどうか。プロキシが SSL を処理する場合に必要となります。" - -#: notebook/notebookapp.py:976 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "" -"\n" -" 非推奨: matplotlib を有効にするにはノートブックで %pylab または %matplotlib\n" -" を実行して下さい。" - -#: notebook/notebookapp.py:988 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "コマンドラインでの --pylab 指定はサポートされなくなりました。" - -#: notebook/notebookapp.py:990 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "ノートブックの中で `%pylab{0}` または `%matplotlib{0}` を使ってください。" - -#: notebook/notebookapp.py:995 -msgid "The directory to use for notebooks and kernels." -msgstr "ノートブックとカーネルが使うディレクトリ。" - -#: notebook/notebookapp.py:1018 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "ノートブックディレクトリが見つかりません: '%r'" - -#: notebook/notebookapp.py:1031 -msgid "DEPRECATED use the nbserver_extensions dict instead" -msgstr "非推奨 nbserver_extensions 辞書を代わりに使用して下さい " - -#: notebook/notebookapp.py:1036 -msgid "server_extensions is deprecated, use nbserver_extensions" -msgstr "server_extensions が非推奨です。 nbserver_extensions を使用して下さい。" - -#: notebook/notebookapp.py:1040 -msgid "Dict of Python modules to load as notebook server extensions.Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order." -msgstr "ノートブックサーバ拡張としてロードする Python モジュールの辞書。エントリー値を使用して拡張のロードを有効または無効にすることができます。 拡張子はアルファベット順にロードされます。" - -#: notebook/notebookapp.py:1049 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "サーバ拡張の読み込み中に例外が発生しましたか?" - -#: notebook/notebookapp.py:1052 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "メッセージが送信される前に iopub で送信可能な最大レート。" - -#: notebook/notebookapp.py:1056 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" -"(bytes/sec)\n" -" ストリーム出力が送信制限される前に iopub で送信可能な最大レート。" - -#: notebook/notebookapp.py:1060 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "" -"(sec) このウィンドウはメッセージとデータの帯域リミット\n" -" をチェックする為に使用されます。" - -#: notebook/notebookapp.py:1071 -#, python-format -msgid "No such file or directory: %s" -msgstr "その様なファイルまたはディレクトリは存在しません: %s" - -#: notebook/notebookapp.py:1141 -msgid "Notebook servers are configured to only be run with a password." -msgstr "ノートブックサーバはパスワードが設定された場合にだけ動作するよう設定されています。" - -#: notebook/notebookapp.py:1142 -msgid "Hint: run the following command to set a password" -msgstr "ヒント: パスワードを設定するには以下のコマンドを実行します" - -#: notebook/notebookapp.py:1143 -msgid "\t$ python -m notebook.auth password" -msgstr "" - -#: notebook/notebookapp.py:1181 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "ポート %i は既に使用されています。他のポートで試して下さい。" - -#: notebook/notebookapp.py:1184 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "ポート %i で待機する権限がありません" - -#: notebook/notebookapp.py:1193 -msgid "ERROR: the notebook server could not be started because no available port could be found." -msgstr "エラー: 有効なポートが見付からなかったためノートブックサーバを起動できませんでした。" - -#: notebook/notebookapp.py:1199 -msgid "[all ip addresses on your system]" -msgstr "[システム上の全ての IP アドレス]" - -#: notebook/notebookapp.py:1223 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "端末は存在しません (%s でエラー発生)" - -#: notebook/notebookapp.py:1259 -msgid "interrupted" -msgstr "中断しました" - -#: notebook/notebookapp.py:1261 -msgid "y" -msgstr "" - -#: notebook/notebookapp.py:1262 -msgid "n" -msgstr "" - -#: notebook/notebookapp.py:1263 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "このノートブックサーバをシャットダウンしますか? (%s/[%s])" - -#: notebook/notebookapp.py:1269 -msgid "Shutdown confirmed" -msgstr "シャットダウンの確認" - -#: notebook/notebookapp.py:1273 -msgid "No answer for 5s:" -msgstr "5秒間に応答がありません:" - -#: notebook/notebookapp.py:1274 -msgid "resuming operation..." -msgstr "操作を再開中..." - -#: notebook/notebookapp.py:1282 -#, python-format -msgid "received signal %s, stopping" -msgstr "シグナル %s を受信。停止します" - -#: notebook/notebookapp.py:1338 -#, python-format -msgid "Error loading server extension %s" -msgstr "サーバ拡張 %s の読み込みエラー" - -#: notebook/notebookapp.py:1369 -#, python-format -msgid "Shutting down %d kernels" -msgstr "%d 個のカーネルをシャットダウンしています" - -#: notebook/notebookapp.py:1375 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "%d 個のアクティブなカーネル" -msgstr[1] "%d 個のアクティブなカーネル" - -#: notebook/notebookapp.py:1379 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"%s" -msgstr "" -"Jupyter Notebook は以下の URL 起動しています:\n" -"%s" - -#: notebook/notebookapp.py:1426 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "root ユーザでの実行は推奨されません。バイパスするには --allow-root を使って下さい。" - -#: notebook/notebookapp.py:1432 -msgid "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." -msgstr "サーバを停止し全てのカーネルをシャットダウンするには Control-C を使って下さい(確認をスキップするには2回)。" - -#: notebook/notebookapp.py:1434 -msgid "Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at http://jupyter.org/community.html." -msgstr "Project Jupyter へようこそ! 利用可能な色々なツールとそれに対応するドキュメントを探索して下さい。プラットフォームへの貢献に興味がある場合は http://jupyter.org/community.html の communityresources セクションにアクセスしてください。" - -#: notebook/notebookapp.py:1445 -#, python-format -msgid "No web browser found: %s." -msgstr "ウェブブラウザが見つかりません: %s" - -#: notebook/notebookapp.py:1450 -#, python-format -msgid "%s does not exist" -msgstr "%s は存在しません" - -#: notebook/notebookapp.py:1484 -msgid "Interrupted..." -msgstr "中断..." - -#: notebook/services/contents/filemanager.py:506 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "ローカルディレクトリからノートブックをサーブ: %s" - -#: notebook/services/contents/manager.py:68 -msgid "Untitled" -msgstr "" diff --git a/notebook/i18n/nbjs.json b/notebook/i18n/nbjs.json deleted file mode 100644 index 6faa829a7..000000000 --- a/notebook/i18n/nbjs.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "domain": "nbjs", - "supported_languages": [ - "fr-FR", - "zh-CN", - "nl", - "ja_JP" - ], - "locale_data": { - "nbjs": { - "": { - "domain": "nbjs" - } - } - } -} diff --git a/notebook/i18n/nbjs.pot b/notebook/i18n/nbjs.pot deleted file mode 100644 index 6a9842c6c..000000000 --- a/notebook/i18n/nbjs.pot +++ /dev/null @@ -1,1935 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-06-27 14:04-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/static/base/js/dialog.js:161 -msgid "Manually edit the JSON below to manipulate the metadata for this cell." -msgstr "" - -#: notebook/static/base/js/dialog.js:163 -msgid "Manually edit the JSON below to manipulate the metadata for this notebook." -msgstr "" - -#: notebook/static/base/js/dialog.js:165 -msgid " We recommend putting custom metadata attributes in an appropriately named substructure, so they don't conflict with those of others." -msgstr "" - -#: notebook/static/base/js/dialog.js:180 -msgid "Edit the metadata" -msgstr "" - -#: notebook/static/base/js/dialog.js:202 -msgid "Edit Notebook Metadata" -msgstr "" - -#: notebook/static/base/js/dialog.js:204 -msgid "Edit Cell Metadata" -msgstr "" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/notebook.js:475 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:859 -#: notebook/static/tree/js/notebooklist.js:1418 -msgid "Cancel" -msgstr "" - -#: notebook/static/base/js/dialog.js:208 -msgid "Edit" -msgstr "" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/kernelselector.js:278 -#: notebook/static/notebook/js/mathjaxutils.js:42 -#: notebook/static/notebook/js/notebook.js:469 -#: notebook/static/notebook/js/notificationarea.js:187 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/newnotebook.js:97 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "OK" -msgstr "" - -#: notebook/static/base/js/dialog.js:208 -msgid "Apply" -msgstr "" - -#: notebook/static/base/js/dialog.js:225 -msgid "WARNING: Could not save invalid JSON." -msgstr "" - -#: notebook/static/base/js/dialog.js:247 -msgid "There are no attachments for this cell." -msgstr "" - -#: notebook/static/base/js/dialog.js:250 -msgid "Current cell attachments" -msgstr "" - -#: notebook/static/base/js/dialog.js:259 -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:46 -msgid "Attachments" -msgstr "" - -#: notebook/static/base/js/dialog.js:283 -msgid "Restore" -msgstr "" - -#: notebook/static/base/js/dialog.js:293 -#: notebook/static/tree/js/notebooklist.js:1018 -msgid "Delete" -msgstr "" - -#: notebook/static/base/js/dialog.js:342 notebook/static/base/js/dialog.js:386 -msgid "Edit attachments" -msgstr "" - -#: notebook/static/base/js/dialog.js:348 -msgid "Edit Notebook Attachments" -msgstr "" - -#: notebook/static/base/js/dialog.js:350 -msgid "Edit Cell Attachments" -msgstr "" - -#: notebook/static/base/js/dialog.js:373 -msgid "Select a file to insert." -msgstr "" - -#: notebook/static/base/js/dialog.js:399 -msgid "Select a file" -msgstr "" - -#: notebook/static/notebook/js/about.js:14 -msgid "You are using Jupyter notebook." -msgstr "" - -#: notebook/static/notebook/js/about.js:16 -msgid "The version of the notebook server is: " -msgstr "" - -#: notebook/static/notebook/js/about.js:22 -msgid "The server is running on this version of Python:" -msgstr "" - -#: notebook/static/notebook/js/about.js:25 -msgid "Waiting for kernel to be available..." -msgstr "" - -#: notebook/static/notebook/js/about.js:27 -msgid "Server Information:" -msgstr "" - -#: notebook/static/notebook/js/about.js:29 -msgid "Current Kernel Information:" -msgstr "" - -#: notebook/static/notebook/js/about.js:32 -msgid "Could not access sys_info variable for version information." -msgstr "" - -#: notebook/static/notebook/js/about.js:34 -msgid "Cannot find sys_info!" -msgstr "" - -#: notebook/static/notebook/js/about.js:38 -msgid "About Jupyter Notebook" -msgstr "" - -#: notebook/static/notebook/js/about.js:47 -msgid "unable to contact kernel" -msgstr "" - -#: notebook/static/notebook/js/actions.js:69 -msgid "toggle rtl layout" -msgstr "" - -#: notebook/static/notebook/js/actions.js:70 -msgid "Toggle the screen directionality between left-to-right and right-to-left" -msgstr "" - -#: notebook/static/notebook/js/actions.js:76 -msgid "edit command mode keyboard shortcuts" -msgstr "" - -#: notebook/static/notebook/js/actions.js:77 -msgid "Open a dialog to edit the command mode keyboard shortcuts" -msgstr "" - -#: notebook/static/notebook/js/actions.js:97 -msgid "restart kernel" -msgstr "" - -#: notebook/static/notebook/js/actions.js:98 -msgid "restart the kernel (no confirmation dialog)" -msgstr "" - -#: notebook/static/notebook/js/actions.js:106 -msgid "confirm restart kernel" -msgstr "" - -#: notebook/static/notebook/js/actions.js:107 -msgid "restart the kernel (with dialog)" -msgstr "" - -#: notebook/static/notebook/js/actions.js:113 -msgid "restart kernel and run all cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:114 -msgid "restart the kernel, then re-run the whole notebook (no confirmation dialog)" -msgstr "" - -#: notebook/static/notebook/js/actions.js:120 -msgid "confirm restart kernel and run all cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:121 -msgid "restart the kernel, then re-run the whole notebook (with dialog)" -msgstr "" - -#: notebook/static/notebook/js/actions.js:127 -msgid "restart kernel and clear output" -msgstr "" - -#: notebook/static/notebook/js/actions.js:128 -msgid "restart the kernel and clear all output (no confirmation dialog)" -msgstr "" - -#: notebook/static/notebook/js/actions.js:134 -msgid "confirm restart kernel and clear output" -msgstr "" - -#: notebook/static/notebook/js/actions.js:135 -msgid "restart the kernel and clear all output (with dialog)" -msgstr "" - -#: notebook/static/notebook/js/actions.js:142 -#: notebook/static/notebook/js/actions.js:143 -msgid "interrupt the kernel" -msgstr "" - -#: notebook/static/notebook/js/actions.js:150 -msgid "run cell and select next" -msgstr "" - -#: notebook/static/notebook/js/actions.js:152 -msgid "run cell, select below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:159 -#: notebook/static/notebook/js/actions.js:160 -msgid "run selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:167 -#: notebook/static/notebook/js/actions.js:168 -msgid "run cell and insert below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:175 -#: notebook/static/notebook/js/actions.js:176 -msgid "run all cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:183 -#: notebook/static/notebook/js/actions.js:184 -msgid "run all cells above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:190 -#: notebook/static/notebook/js/actions.js:191 -msgid "run all cells below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:197 -#: notebook/static/notebook/js/actions.js:198 -msgid "enter command mode" -msgstr "" - -#: notebook/static/notebook/js/actions.js:205 -#: notebook/static/notebook/js/actions.js:206 -msgid "insert image" -msgstr "" - -#: notebook/static/notebook/js/actions.js:213 -#: notebook/static/notebook/js/actions.js:214 -msgid "cut cell attachments" -msgstr "" - -#: notebook/static/notebook/js/actions.js:221 -#: notebook/static/notebook/js/actions.js:222 -msgid "copy cell attachments" -msgstr "" - -#: notebook/static/notebook/js/actions.js:229 -#: notebook/static/notebook/js/actions.js:230 -msgid "paste cell attachments" -msgstr "" - -#: notebook/static/notebook/js/actions.js:237 -#: notebook/static/notebook/js/actions.js:238 -msgid "split cell at cursor" -msgstr "" - -#: notebook/static/notebook/js/actions.js:245 -#: notebook/static/notebook/js/actions.js:246 -msgid "enter edit mode" -msgstr "" - -#: notebook/static/notebook/js/actions.js:253 -msgid "select previous cell" -msgstr "" - -#: notebook/static/notebook/js/actions.js:254 -msgid "select cell above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:265 -msgid "select next cell" -msgstr "" - -#: notebook/static/notebook/js/actions.js:266 -msgid "select cell below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:277 -msgid "extend selection above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:278 -msgid "extend selected cells above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:289 -msgid "extend selection below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:290 -msgid "extend selected cells below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:301 -#: notebook/static/notebook/js/actions.js:302 -msgid "cut selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:312 -#: notebook/static/notebook/js/actions.js:313 -msgid "copy selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:327 -#: notebook/static/notebook/js/actions.js:328 -msgid "paste cells above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:335 -#: notebook/static/notebook/js/actions.js:336 -msgid "paste cells below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:344 -#: notebook/static/notebook/js/actions.js:345 -msgid "insert cell above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:354 -#: notebook/static/notebook/js/actions.js:355 -msgid "insert cell below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:365 -#: notebook/static/notebook/js/actions.js:366 -msgid "change cell to code" -msgstr "" - -#: notebook/static/notebook/js/actions.js:373 -#: notebook/static/notebook/js/actions.js:374 -msgid "change cell to markdown" -msgstr "" - -#: notebook/static/notebook/js/actions.js:381 -#: notebook/static/notebook/js/actions.js:382 -msgid "change cell to raw" -msgstr "" - -#: notebook/static/notebook/js/actions.js:389 -#: notebook/static/notebook/js/actions.js:390 -msgid "change cell to heading 1" -msgstr "" - -#: notebook/static/notebook/js/actions.js:397 -#: notebook/static/notebook/js/actions.js:398 -msgid "change cell to heading 2" -msgstr "" - -#: notebook/static/notebook/js/actions.js:405 -#: notebook/static/notebook/js/actions.js:406 -msgid "change cell to heading 3" -msgstr "" - -#: notebook/static/notebook/js/actions.js:413 -#: notebook/static/notebook/js/actions.js:414 -msgid "change cell to heading 4" -msgstr "" - -#: notebook/static/notebook/js/actions.js:421 -#: notebook/static/notebook/js/actions.js:422 -msgid "change cell to heading 5" -msgstr "" - -#: notebook/static/notebook/js/actions.js:429 -#: notebook/static/notebook/js/actions.js:430 -msgid "change cell to heading 6" -msgstr "" - -#: notebook/static/notebook/js/actions.js:437 -msgid "toggle cell output" -msgstr "" - -#: notebook/static/notebook/js/actions.js:438 -msgid "toggle output of selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:445 -msgid "toggle cell scrolling" -msgstr "" - -#: notebook/static/notebook/js/actions.js:446 -msgid "toggle output scrolling of selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:453 -msgid "clear cell output" -msgstr "" - -#: notebook/static/notebook/js/actions.js:454 -msgid "clear output of selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:460 -msgid "move cells down" -msgstr "" - -#: notebook/static/notebook/js/actions.js:461 -msgid "move selected cells down" -msgstr "" - -#: notebook/static/notebook/js/actions.js:469 -msgid "move cells up" -msgstr "" - -#: notebook/static/notebook/js/actions.js:470 -msgid "move selected cells up" -msgstr "" - -#: notebook/static/notebook/js/actions.js:478 -#: notebook/static/notebook/js/actions.js:479 -msgid "toggle line numbers" -msgstr "" - -#: notebook/static/notebook/js/actions.js:486 -#: notebook/static/notebook/js/actions.js:487 -msgid "show keyboard shortcuts" -msgstr "" - -#: notebook/static/notebook/js/actions.js:494 -msgid "delete cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:495 -msgid "delete selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:502 -#: notebook/static/notebook/js/actions.js:503 -msgid "undo cell deletion" -msgstr "" - -#: notebook/static/notebook/js/actions.js:512 -msgid "merge cell with previous cell" -msgstr "" - -#: notebook/static/notebook/js/actions.js:513 -msgid "merge cell above" -msgstr "" - -#: notebook/static/notebook/js/actions.js:519 -msgid "merge cell with next cell" -msgstr "" - -#: notebook/static/notebook/js/actions.js:520 -msgid "merge cell below" -msgstr "" - -#: notebook/static/notebook/js/actions.js:527 -#: notebook/static/notebook/js/actions.js:528 -msgid "merge selected cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:535 -msgid "merge cells" -msgstr "" - -#: notebook/static/notebook/js/actions.js:536 -msgid "merge selected cells, or current cell with cell below if only one cell is selected" -msgstr "" - -#: notebook/static/notebook/js/actions.js:549 -msgid "show command pallette" -msgstr "" - -#: notebook/static/notebook/js/actions.js:550 -msgid "open the command palette" -msgstr "" - -#: notebook/static/notebook/js/actions.js:557 -msgid "toggle all line numbers" -msgstr "" - -#: notebook/static/notebook/js/actions.js:558 -msgid "toggles line numbers in all cells, and persist the setting" -msgstr "" - -#: notebook/static/notebook/js/actions.js:569 -msgid "show all line numbers" -msgstr "" - -#: notebook/static/notebook/js/actions.js:570 -msgid "show line numbers in all cells, and persist the setting" -msgstr "" - -#: notebook/static/notebook/js/actions.js:579 -msgid "hide all line numbers" -msgstr "" - -#: notebook/static/notebook/js/actions.js:580 -msgid "hide line numbers in all cells, and persist the setting" -msgstr "" - -#: notebook/static/notebook/js/actions.js:589 -msgid "toggle header" -msgstr "" - -#: notebook/static/notebook/js/actions.js:590 -msgid "switch between showing and hiding the header" -msgstr "" - -#: notebook/static/notebook/js/actions.js:605 -#: notebook/static/notebook/js/actions.js:606 -msgid "show the header" -msgstr "" - -#: notebook/static/notebook/js/actions.js:615 -#: notebook/static/notebook/js/actions.js:616 -msgid "hide the header" -msgstr "" - -#: notebook/static/notebook/js/actions.js:646 -msgid "toggle toolbar" -msgstr "" - -#: notebook/static/notebook/js/actions.js:647 -msgid "switch between showing and hiding the toolbar" -msgstr "" - -#: notebook/static/notebook/js/actions.js:660 -#: notebook/static/notebook/js/actions.js:661 -msgid "show the toolbar" -msgstr "" - -#: notebook/static/notebook/js/actions.js:669 -#: notebook/static/notebook/js/actions.js:670 -msgid "hide the toolbar" -msgstr "" - -#: notebook/static/notebook/js/actions.js:678 -#: notebook/static/notebook/js/actions.js:679 -msgid "close the pager" -msgstr "" - -#: notebook/static/notebook/js/actions.js:704 -msgid "ignore" -msgstr "" - -#: notebook/static/notebook/js/actions.js:710 -#: notebook/static/notebook/js/actions.js:711 -msgid "move cursor up" -msgstr "" - -#: notebook/static/notebook/js/actions.js:731 -#: notebook/static/notebook/js/actions.js:732 -msgid "move cursor down" -msgstr "" - -#: notebook/static/notebook/js/actions.js:750 -#: notebook/static/notebook/js/actions.js:751 -msgid "scroll notebook down" -msgstr "" - -#: notebook/static/notebook/js/actions.js:760 -#: notebook/static/notebook/js/actions.js:761 -msgid "scroll notebook up" -msgstr "" - -#: notebook/static/notebook/js/actions.js:770 -msgid "scroll cell center" -msgstr "" - -#: notebook/static/notebook/js/actions.js:771 -msgid "Scroll the current cell to the center" -msgstr "" - -#: notebook/static/notebook/js/actions.js:781 -msgid "scroll cell top" -msgstr "" - -#: notebook/static/notebook/js/actions.js:782 -msgid "Scroll the current cell to the top" -msgstr "" - -#: notebook/static/notebook/js/actions.js:792 -msgid "duplicate notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:793 -msgid "Create and open a copy of the current notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:799 -msgid "trust notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:800 -msgid "Trust the current notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:806 -msgid "rename notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:807 -msgid "Rename the current notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:813 -msgid "toggle all cells output collapsed" -msgstr "" - -#: notebook/static/notebook/js/actions.js:814 -msgid "Toggle the hidden state of all output areas" -msgstr "" - -#: notebook/static/notebook/js/actions.js:820 -msgid "toggle all cells output scrolled" -msgstr "" - -#: notebook/static/notebook/js/actions.js:821 -msgid "Toggle the scrolling state of all output areas" -msgstr "" - -#: notebook/static/notebook/js/actions.js:828 -msgid "clear all cells output" -msgstr "" - -#: notebook/static/notebook/js/actions.js:829 -msgid "Clear the content of all the outputs" -msgstr "" - -#: notebook/static/notebook/js/actions.js:835 -msgid "save notebook" -msgstr "" - -#: notebook/static/notebook/js/actions.js:836 -msgid "Save and Checkpoint" -msgstr "" - -#: notebook/static/notebook/js/cell.js:79 -msgid "Warning: accessing Cell.cm_config directly is deprecated." -msgstr "" - -#: notebook/static/notebook/js/cell.js:763 -#, python-format -msgid "Unrecognized cell type: %s" -msgstr "" - -#: notebook/static/notebook/js/cell.js:777 -msgid "Unrecognized cell type" -msgstr "" - -#: notebook/static/notebook/js/celltoolbar.js:296 -#, python-format -msgid "Error in cell toolbar callback %s" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:53 -#, python-format -msgid "Clipboard types: %s" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:96 -msgid "Dialog for paste from system clipboard" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:109 -msgid "Ctrl-V" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:111 -msgid "Cmd-V" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:113 -#, python-format -msgid "Press %s again to paste" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:116 -msgid "Why is this needed? " -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:118 -msgid "We can't get paste events in this browser without a text box. " -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:119 -msgid "There's an invisible text box focused in this dialog." -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:125 -#, python-format -msgid "%s to paste" -msgstr "" - -#: notebook/static/notebook/js/codecell.js:310 -msgid "Can't execute cell since kernel is not set." -msgstr "" - -#: notebook/static/notebook/js/codecell.js:472 -msgid "In" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:269 -#, python-format -msgid "Could not find a kernel matching %s. Please select a kernel:" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Continue Without Kernel" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Set Kernel" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:281 -msgid "Kernel not found" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:319 -#: notebook/static/tree/js/newnotebook.js:99 -msgid "Creating Notebook Failed" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:320 -#: notebook/static/tree/js/notebooklist.js:1360 -#, python-format -msgid "The error was: %s" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:54 -msgid "Run" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:76 -msgid "Code" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:77 -msgid "Markdown" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:78 -msgid "Raw NBConvert" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:79 -msgid "Heading" -msgstr "" - -#: notebook/static/notebook/js/maintoolbar.js:115 -msgid "unrecognized cell type:" -msgstr "" - -#: notebook/static/notebook/js/mathjaxutils.js:45 -#, python-format -msgid "Failed to retrieve MathJax from '%s'" -msgstr "" - -#: notebook/static/notebook/js/mathjaxutils.js:47 -msgid "Math/LaTeX rendering will be disabled." -msgstr "" - -#: notebook/static/notebook/js/menubar.js:220 -msgid "Trusted Notebook" -msgstr "" - -#: notebook/static/notebook/js/menubar.js:226 -msgid "Trust Notebook" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16 -#: notebook/static/notebook/js/menubar.js:383 -msgid "None" -msgstr "" - -#: notebook/static/notebook/js/menubar.js:406 -msgid "No checkpoints" -msgstr "" - -#: notebook/static/notebook/js/menubar.js:465 -msgid "Opens in a new window" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:431 -msgid "Autosave in progress, latest changes may be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:433 -msgid "Unsaved changes will be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:438 -msgid "The Kernel is busy, outputs may be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:461 -msgid "This notebook is version %1$s, but we only fully support up to %2$s." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:463 -msgid "You can still work with this notebook, but cell and output types introduced in later notebook versions will not be available." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:470 -msgid "Restart and Run All Cells" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:471 -msgid "Restart and Clear All Outputs" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:472 -msgid "Restart" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:473 -msgid "Continue Running" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:474 -msgid "Reload" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:476 -msgid "Overwrite" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:477 -msgid "Trust" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:478 -msgid "Revert" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:483 -msgid "Newer Notebook" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:1548 -msgid "Use markdown headings" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:1550 -msgid "Jupyter no longer uses special heading cells. Instead, write your headings in Markdown cells using # characters:" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:1553 -msgid "## This is a level 2 heading" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2248 -msgid "Restart kernel and re-run the whole notebook?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2250 -msgid "Are you sure you want to restart the current kernel and re-execute the whole notebook? All variables and outputs will be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2275 -msgid "Restart kernel and clear all output?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2277 -msgid "Do you want to restart the current kernel and clear all output? All variables and outputs will be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Restart kernel?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2324 -msgid "Do you want to restart the current kernel? All variables will be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2320 -msgid "Shutdown kernel?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Do you want to shutdown the current kernel? All variables will be lost." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2734 -msgid "Notebook changed" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2735 -msgid "The notebook file has changed on disk since the last time we opened or saved it. Do you want to overwrite the file on disk with the version open here, or load the version on disk (reload the page) ?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2782 -#: notebook/static/notebook/js/notebook.js:2990 -msgid "Notebook validation failed" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2785 -msgid "The save operation succeeded, but the notebook does not appear to be valid. The validation error was:" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2836 -msgid "A trusted Jupyter notebook may execute hidden malicious code when you open it. Selecting trust will immediately reload this notebook in a trusted state. For more information, see the Jupyter security documentation: " -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2840 -msgid "here" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2848 -msgid "Trust this notebook?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2981 -msgid "Notebook failed to load" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2983 -msgid "The error was: " -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2987 -msgid "See the error console for details." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2995 -msgid "The notebook also failed validation:" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:2997 -msgid "An invalid notebook may not function properly. The validation error was:" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3036 -#, python-format -msgid "This notebook has been converted from an older notebook format to the current notebook format v(%s)." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3038 -#, python-format -msgid "This notebook has been converted from a newer notebook format to the current notebook format v(%s)." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3046 -msgid "The next time you save this notebook, the current notebook format will be used." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3051 -msgid "Older versions of Jupyter may not be able to read the new format." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3053 -msgid "Some features of the original notebook may not be available." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3056 -msgid "To preserve the original version, close the notebook without saving it." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3061 -msgid "Notebook converted" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3083 -msgid "(No name)" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3131 -#, python-format -msgid "An unknown error occurred while loading this notebook. This version can load notebook formats %s or earlier. See the server log for details." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3142 -msgid "Error loading notebook" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3243 -msgid "Are you sure you want to revert the notebook to the latest checkpoint?" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3246 -msgid "This cannot be undone." -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3249 -msgid "The checkpoint was last updated at:" -msgstr "" - -#: notebook/static/notebook/js/notebook.js:3260 -msgid "Revert notebook to checkpoint" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:77 -#: notebook/static/notebook/js/tour.js:61 -#: notebook/static/notebook/js/tour.js:67 -msgid "Edit Mode" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:84 -#: notebook/static/notebook/js/notificationarea.js:88 -#: notebook/static/notebook/js/tour.js:54 -msgid "Command Mode" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:95 -msgid "Kernel Created" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:99 -msgid "Connecting to kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:103 -msgid "Not Connected" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:106 -msgid "click to reconnect" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:115 -msgid "Restarting kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:129 -msgid "Kernel Restarting" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:130 -msgid "The kernel appears to have died. It will restart automatically." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:140 -#: notebook/static/notebook/js/notificationarea.js:198 -#: notebook/static/notebook/js/notificationarea.js:218 -msgid "Dead kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:141 -#: notebook/static/notebook/js/notificationarea.js:219 -#: notebook/static/notebook/js/notificationarea.js:266 -msgid "Kernel Dead" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:145 -msgid "Interrupting kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:151 -msgid "No Connection to Kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:161 -msgid "A connection to the notebook server could not be established. The notebook will continue trying to reconnect. Check your network connection or notebook server configuration." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:166 -msgid "Connection failed" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:179 -msgid "No kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:180 -msgid "Kernel is not running" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Don't Restart" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Try Restarting Now" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:191 -msgid "The kernel has died, and the automatic restart has failed. It is possible the kernel cannot be restarted. If you are not able to restart the kernel, you will still be able to save the notebook, but running code will no longer work until the notebook is reopened." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:225 -msgid "No Kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:252 -msgid "Failed to start the kernel" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:272 -#: notebook/static/notebook/js/notificationarea.js:292 -#: notebook/static/notebook/js/notificationarea.js:306 -msgid "Kernel Busy" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:273 -msgid "Kernel starting, please wait..." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:279 -#: notebook/static/notebook/js/notificationarea.js:286 -msgid "Kernel Idle" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:280 -msgid "Kernel ready" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:297 -msgid "Using kernel: " -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:298 -msgid "Only candidate for language: %1$s was %2$s." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:319 -msgid "Loading notebook" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:322 -msgid "Notebook loaded" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:325 -msgid "Saving notebook" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:328 -msgid "Notebook saved" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:331 -msgid "Notebook save failed" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:334 -msgid "Notebook copy failed" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:339 -msgid "Checkpoint created" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:347 -msgid "Checkpoint failed" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:350 -msgid "Checkpoint deleted" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:353 -msgid "Checkpoint delete failed" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:356 -msgid "Restoring to checkpoint..." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:359 -msgid "Checkpoint restore failed" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:364 -msgid "Autosave disabled" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:367 -#, python-format -msgid "Saving every %d sec." -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:383 -msgid "Trusted" -msgstr "" - -#: notebook/static/notebook/js/notificationarea.js:385 -msgid "Not Trusted" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:75 -msgid "click to expand output" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:79 -msgid "click to expand output; double click to hide output" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:167 -msgid "click to unscroll output; double click to hide" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:174 -msgid "click to scroll output; double click to hide" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:422 -msgid "Javascript error adding output!" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:427 -msgid "See your browser Javascript console for more details." -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:468 -#, python-format -msgid "Out[%d]:" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:577 -#, python-format -msgid "Unrecognized output: %s" -msgstr "" - -#: notebook/static/notebook/js/pager.js:36 -msgid "Open the pager in an external window" -msgstr "" - -#: notebook/static/notebook/js/pager.js:45 -msgid "Close the pager" -msgstr "" - -#: notebook/static/notebook/js/pager.js:148 -msgid "Jupyter Pager" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:39 -#: notebook/static/notebook/js/quickhelp.js:49 -#: notebook/static/notebook/js/quickhelp.js:50 -msgid "go to cell start" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:40 -#: notebook/static/notebook/js/quickhelp.js:51 -#: notebook/static/notebook/js/quickhelp.js:52 -msgid "go to cell end" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:41 -#: notebook/static/notebook/js/quickhelp.js:53 -msgid "go one word left" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:42 -#: notebook/static/notebook/js/quickhelp.js:54 -msgid "go one word right" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:43 -#: notebook/static/notebook/js/quickhelp.js:55 -msgid "delete word before" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:44 -#: notebook/static/notebook/js/quickhelp.js:56 -msgid "delete word after" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:61 -msgid "code completion or indent" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:62 -msgid "tooltip" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:63 -msgid "indent" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:64 -msgid "dedent" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:65 -msgid "select all" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:66 -msgid "undo" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:67 -#: notebook/static/notebook/js/quickhelp.js:68 -msgid "redo" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:102 -#: notebook/static/notebook/js/quickhelp.js:243 -msgid "Shift" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:103 -msgid "Alt" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:104 -msgid "Up" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:105 -msgid "Down" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:106 -msgid "Left" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:107 -msgid "Right" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:108 -#: notebook/static/notebook/js/quickhelp.js:246 -msgid "Tab" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:109 -msgid "Caps Lock" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:110 -#: notebook/static/notebook/js/quickhelp.js:269 -msgid "Esc" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:111 -msgid "Ctrl" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:112 -#: notebook/static/notebook/js/quickhelp.js:290 -msgid "Enter" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:113 -msgid "Page Up" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:114 -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "Page Down" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:115 -msgid "Home" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:116 -msgid "End" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:117 -#: notebook/static/notebook/js/quickhelp.js:245 -msgid "Space" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:118 -msgid "Backspace" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:119 -msgid "Minus" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "PageUp" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:197 -msgid "The Jupyter Notebook has two different keyboard input modes." -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:199 -msgid "Edit mode allows you to type code or text into a cell and is indicated by a green cell border." -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:201 -msgid "Command mode binds the keyboard to notebook level commands and is indicated by a grey cell border with a blue left margin." -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:222 -#: notebook/static/notebook/js/tooltip.js:58 -#: notebook/static/notebook/js/tooltip.js:69 -msgid "Close" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:225 -msgid "Keyboard shortcuts" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:240 -msgid "Command" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:241 -msgid "Control" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:242 -msgid "Option" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:244 -msgid "Return" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:270 -#, python-format -msgid "Command Mode (press %s to enable)" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:272 -msgid "Edit Shortcuts" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:275 -msgid "edit command-mode keyboard shortcuts" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:292 -#, python-format -msgid "Edit Mode (press %s to enable)" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:49 -msgid "Autosave Failed!" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:846 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Rename" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:78 -#: notebook/static/tree/js/notebooklist.js:837 -msgid "Enter a new notebook name:" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:86 -msgid "Rename Notebook" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:98 -msgid "Invalid notebook name. Notebook names must have 1 or more characters and can contain any characters except :/\\. Please enter a new notebook name:" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:103 -msgid "Renaming..." -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:109 -msgid "Unknown error" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:178 -msgid "no checkpoint" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:193 -#, python-format -msgid "Last Checkpoint: %s" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:217 -msgid "(unsaved changes)" -msgstr "" - -#: notebook/static/notebook/js/savewidget.js:219 -msgid "(autosaved)" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:74 -#, python-format -msgid "Warning: too many matches (%d). Some changes might not be shown or applied." -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:77 -#, python-format -msgid "%d match" -msgid_plural "%d matches" -msgstr[0] "" -msgstr[1] "" - -#: notebook/static/notebook/js/searchandreplace.js:145 -msgid "More than 100 matches, aborting" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:166 -msgid "Use regex (JavaScript regex syntax)" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:174 -msgid "Replace in selected cells" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:181 -msgid "Match case" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:187 -msgid "Find" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:203 -msgid "Replace" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:255 -msgid "No matches, invalid or empty regular expression" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:370 -msgid "Replace All" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:374 -msgid "Find and Replace" -msgstr "" - -#: notebook/static/notebook/js/searchandreplace.js:400 -#: notebook/static/notebook/js/searchandreplace.js:401 -msgid "find and replace" -msgstr "" - -#: notebook/static/notebook/js/textcell.js:551 -msgid "Write raw LaTeX or other formats here, for use with nbconvert. It will not be rendered in the notebook. When passing through nbconvert, a Raw Cell's content is added to the output unmodified." -msgstr "" - -#: notebook/static/notebook/js/tooltip.js:41 -msgid "Grow the tooltip vertically (press shift-tab twice)" -msgstr "" - -#: notebook/static/notebook/js/tooltip.js:48 -msgid "show the current docstring in pager (press shift-tab 4 times)" -msgstr "" - -#: notebook/static/notebook/js/tooltip.js:49 -msgid "Open in Pager" -msgstr "" - -#: notebook/static/notebook/js/tooltip.js:68 -msgid "Tooltip will linger for 10 seconds while you type" -msgstr "" - -#: notebook/static/notebook/js/tour.js:27 -msgid "Welcome to the Notebook Tour" -msgstr "" - -#: notebook/static/notebook/js/tour.js:30 -msgid "You can use the left and right arrow keys to go backwards and forwards." -msgstr "" - -#: notebook/static/notebook/js/tour.js:33 -msgid "Filename" -msgstr "" - -#: notebook/static/notebook/js/tour.js:35 -msgid "Click here to change the filename for this notebook." -msgstr "" - -#: notebook/static/notebook/js/tour.js:39 -msgid "Notebook Menubar" -msgstr "" - -#: notebook/static/notebook/js/tour.js:40 -msgid "The menubar has menus for actions on the notebook, its cells, and the kernel it communicates with." -msgstr "" - -#: notebook/static/notebook/js/tour.js:44 -msgid "Notebook Toolbar" -msgstr "" - -#: notebook/static/notebook/js/tour.js:45 -msgid "The toolbar has buttons for the most common actions. Hover your mouse over each button for more information." -msgstr "" - -#: notebook/static/notebook/js/tour.js:48 -msgid "Mode Indicator" -msgstr "" - -#: notebook/static/notebook/js/tour.js:50 -msgid "The Notebook has two modes: Edit Mode and Command Mode. In this area, an indicator can appear to tell you which mode you are in." -msgstr "" - -#: notebook/static/notebook/js/tour.js:58 -msgid "Right now you are in Command Mode, and many keyboard shortcuts are available. In this mode, no icon is displayed in the indicator area." -msgstr "" - -#: notebook/static/notebook/js/tour.js:64 -msgid "Pressing Enter or clicking in the input text area of the cell switches to Edit Mode." -msgstr "" - -#: notebook/static/notebook/js/tour.js:70 -msgid "Notice that the border around the currently active cell changed color. Typing will insert text into the currently active cell." -msgstr "" - -#: notebook/static/notebook/js/tour.js:73 -msgid "Back to Command Mode" -msgstr "" - -#: notebook/static/notebook/js/tour.js:76 -msgid "Pressing Esc or clicking outside of the input text area takes you back to Command Mode." -msgstr "" - -#: notebook/static/notebook/js/tour.js:79 -msgid "Keyboard Shortcuts" -msgstr "" - -#: notebook/static/notebook/js/tour.js:91 -msgid "You can click here to get a list of all of the keyboard shortcuts." -msgstr "" - -#: notebook/static/notebook/js/tour.js:94 -#: notebook/static/notebook/js/tour.js:100 -msgid "Kernel Indicator" -msgstr "" - -#: notebook/static/notebook/js/tour.js:97 -msgid "This is the Kernel indicator. It looks like this when the Kernel is idle." -msgstr "" - -#: notebook/static/notebook/js/tour.js:103 -msgid "The Kernel indicator looks like this when the Kernel is busy." -msgstr "" - -#: notebook/static/notebook/js/tour.js:107 -msgid "Interrupting the Kernel" -msgstr "" - -#: notebook/static/notebook/js/tour.js:109 -msgid "To cancel a computation in progress, you can click here." -msgstr "" - -#: notebook/static/notebook/js/tour.js:114 -msgid "Notification Area" -msgstr "" - -#: notebook/static/notebook/js/tour.js:115 -msgid "Messages in response to user actions (Save, Interrupt, etc.) appear here." -msgstr "" - -#: notebook/static/notebook/js/tour.js:117 -msgid "End of Tour" -msgstr "" - -#: notebook/static/notebook/js/tour.js:120 -msgid "This concludes the Jupyter Notebook User Interface Tour." -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32 -msgid "Edit Attachments" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:19 -msgid "Cell" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:29 -#: notebook/static/notebook/js/celltoolbarpresets/default.js:47 -msgid "Edit Metadata" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22 -msgid "Custom" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32 -msgid "Set the MIME type of the raw cell:" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40 -msgid "Raw Cell MIME Type" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74 -msgid "Raw NBConvert Format" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81 -msgid "Raw Cell Format" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15 -msgid "Slide" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:16 -msgid "Sub-Slide" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:17 -msgid "Fragment" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:18 -msgid "Skip" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:19 -msgid "Notes" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35 -msgid "Slide Type" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41 -msgid "Slideshow" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:133 -msgid "Add tag" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163 -msgid "Edit the list of tags below. All whitespace is treated as tag separators." -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172 -msgid "Edit the tags" -msgstr "" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186 -msgid "Edit Tags" -msgstr "" - -#: notebook/static/tree/js/kernellist.js:86 -#: notebook/static/tree/js/terminallist.js:105 -msgid "Shutdown" -msgstr "" - -#: notebook/static/tree/js/newnotebook.js:70 -#, python-format -msgid "Create a new notebook with %s" -msgstr "" - -#: notebook/static/tree/js/newnotebook.js:101 -msgid "An error occurred while creating a new notebook." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:122 -msgid "Creating File Failed" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:124 -msgid "An error occurred while creating a new file." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:142 -msgid "Creating Folder Failed" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:144 -msgid "An error occurred while creating a new folder." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:271 -msgid "Failed to read file" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:272 -#, python-format -msgid "Failed to read file %s" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:283 -#, python-format -msgid "The file size is %d MB. Do you still want to upload it?" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:286 -msgid "Large file size warning" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:355 -msgid "Server error: " -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:390 -msgid "The notebook list is empty." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:463 -msgid "Click here to rename, delete, etc." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:503 -msgid "Running" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:835 -msgid "Enter a new file name:" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:836 -msgid "Enter a new directory name:" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:838 -msgid "Enter a new name:" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:843 -msgid "Rename file" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:844 -msgid "Rename directory" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:845 -msgid "Rename notebook" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Move" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:875 -msgid "An error occurred while renaming \"%1$s\" to \"%2$s\"." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:878 -msgid "Rename Failed" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:927 -#, python-format -msgid "Enter a new destination directory path for this item:" -msgid_plural "Enter a new destination directory path for these %d items:" -msgstr[0] "" -msgstr[1] "" - -#: notebook/static/tree/js/notebooklist.js:940 -#, python-format -msgid "Move an Item" -msgid_plural "Move %d Items" -msgstr[0] "" -msgstr[1] "" - -#: notebook/static/tree/js/notebooklist.js:959 -msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:961 -msgid "Move Failed" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1007 -#, python-format -msgid "Are you sure you want to permanently delete: \"%s\"?" -msgid_plural "Are you sure you want to permanently delete the %d files or folders selected?" -msgstr[0] "" -msgstr[1] "" - -#: notebook/static/tree/js/notebooklist.js:1035 -#, python-format -msgid "An error occurred while deleting \"%s\"." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1037 -msgid "Delete Failed" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1078 -#, python-format -msgid "Are you sure you want to duplicate: \"%s\"?" -msgid_plural "Are you sure you want to duplicate the %d files selected?" -msgstr[0] "" -msgstr[1] "" - -#: notebook/static/tree/js/notebooklist.js:1088 -msgid "Duplicate" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1102 -#, python-format -msgid "An error occurred while duplicating \"%s\"." -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1104 -msgid "Duplicate Failed" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1323 -msgid "Upload" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1332 -msgid "Invalid file name" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1333 -msgid "File names must be at least one character and not start with a period" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1362 -msgid "Cannot upload invalid Notebook" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1395 -#, python-format -msgid "There is already a file named \"%s\". Do you want to replace it?" -msgstr "" - -#: notebook/static/tree/js/notebooklist.js:1397 -msgid "Replace file" -msgstr "" - diff --git a/notebook/i18n/nbui.pot b/notebook/i18n/nbui.pot deleted file mode 100644 index 64f12097f..000000000 --- a/notebook/i18n/nbui.pot +++ /dev/null @@ -1,732 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-07 12:48-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "" - -#: notebook/templates/logout.html:24 -#, python-format -msgid "Proceed to the dashboard" -msgstr "" - -#: notebook/templates/logout.html:26 -#, python-format -msgid "Proceed to the login page" -msgstr "" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "" - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "" - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "" - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "" - -#: notebook/templates/notebook.html:205 -msgid "All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells" -msgstr "" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "" - -#: notebook/templates/notebook.html:209 -msgid "Contents will be sent to the kernel for execution, and output will display in the footer of cell" -msgstr "" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "" - -#: notebook/templates/notebook.html:319 -msgid "About Jupyter Notebook" -msgstr "" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "" - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "" - -#: notebook/templates/page.html:121 -msgid "dashboard" -msgstr "" - -#: notebook/templates/page.html:132 -msgid "Logout" -msgstr "" - -#: notebook/templates/page.html:134 -msgid "Login" -msgstr "" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "" - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "" - -#: notebook/templates/notebook.html:278 -#: notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "" - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "" - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "" - -#: notebook/templates/tree.html:98 -msgid "Folders" -msgstr "" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "" - -#: notebook/templates/tree.html:99 -msgid "All Notebooks" -msgstr "" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "" - -#: notebook/templates/tree.html:100 -msgid "Running" -msgstr "" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "" - -#: notebook/templates/tree.html:101 -msgid "Files" -msgstr "" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "" - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "" - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "" - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "" - -#: notebook/templates/tree.html:179 -msgid "See 'IPython parallel' for installation details." -msgstr "" - diff --git a/notebook/i18n/nl/LC_MESSAGES/nbjs.json b/notebook/i18n/nl/LC_MESSAGES/nbjs.json deleted file mode 100644 index cd1a23c76..000000000 --- a/notebook/i18n/nl/LC_MESSAGES/nbjs.json +++ /dev/null @@ -1,1353 +0,0 @@ -{ - "domain": "nbjs", - "locale_data": { - "nbjs": { - "": { - "domain": "nbjs" - }, - "Manually edit the JSON below to manipulate the metadata for this cell.": [ - "Bewerk de JSON eronder handmatig om de metagegevens voor deze cel te manipuleren." - ], - "Manually edit the JSON below to manipulate the metadata for this notebook.": [ - "Bewerk de JSON eronder handmatig om de metagegevens voor dit notebook te manipuleren." - ], - " We recommend putting custom metadata attributes in an appropriately named substructure, so they don't conflict with those of others.": [ - " We raden u aan aangepaste metagegevenskenmerken in een op de juiste naam genoemde substructuur te plaatsen, zodat ze niet in strijd zijn met die van anderen." - ], - "Edit the metadata": [ - "De metagegevens bewerken" - ], - "Edit Notebook Metadata": [ - "Metagegevens van notebook bewerken" - ], - "Edit Cell Metadata": [ - "Celmetagegevens bewerken" - ], - "Cancel": [ - "Annuleren" - ], - "Edit": [ - "Bewerken" - ], - "OK": [ - "OK" - ], - "Apply": [ - "Toepassen" - ], - "WARNING: Could not save invalid JSON.": [ - "WAARSCHUWING: Kan ongeldige JSON niet opslaan." - ], - "There are no attachments for this cell.": [ - "Er zijn geen bijlagen voor deze cel." - ], - "Current cell attachments": [ - "Huidige celbijlagen" - ], - "Attachments": [ - "Bijlagen" - ], - "Restore": [ - "Herstellen" - ], - "Delete": [ - "Verwijderen" - ], - "Edit attachments": [ - "Bijlagen bewerken" - ], - "Edit Notebook Attachments": [ - "Notebook-bijlagen bewerken" - ], - "Edit Cell Attachments": [ - "Celbijlagen bewerken" - ], - "Select a file to insert.": [ - "Selecteer een bestand dat u wilt invoegen." - ], - "Select a file": [ - "Een bestand selecteren" - ], - "You are using Jupyter notebook.": [ - "U gebruikt Jupyter notebook." - ], - "The version of the notebook server is: ": [ - "De versie van de notebookserver is: " - ], - "The server is running on this version of Python:": [ - "De server draait op deze versie van Python:" - ], - "Waiting for kernel to be available...": [ - "Wachten tot kernel beschikbaar is..." - ], - "Server Information:": [ - "Servergegevens:" - ], - "Current Kernel Information:": [ - "Informatie van huidige kernel:" - ], - "Could not access sys_info variable for version information.": [ - "Kon geen toegang krijgen tot sys_info variabele voor versie-informatie." - ], - "Cannot find sys_info!": [ - "Ik kan sys_info niet vinden!" - ], - "About Jupyter Notebook": [ - "Over Jupyter Notebook" - ], - "unable to contact kernel": [ - "kan de kernel niet bereiken" - ], - "toggle rtl layout": [ - "rtl-indeling in- en uitschakelen" - ], - "Toggle the screen directionality between left-to-right and right-to-left": [ - "De richting van het scherm schakelen tussen links-naar-rechts en rechts-naar-links" - ], - "edit command mode keyboard shortcuts": [ - "sneltoetsen in de opdrachtmodus bewerken" - ], - "Open a dialog to edit the command mode keyboard shortcuts": [ - "Een dialoogvenster openen om sneltoetsen in de opdrachtmodus te bewerken" - ], - "restart kernel": [ - "kernel herstarten" - ], - "restart the kernel (no confirmation dialog)": [ - "de kernel herstarten (geen bevestigingsdialoogvenster)" - ], - "confirm restart kernel": [ - "bevestig herstart van kernel" - ], - "restart the kernel (with dialog)": [ - "de kernel herstarten (met dialoogvenster)" - ], - "restart kernel and run all cells": [ - "kernel herstarten en alle cellen uitvoeren" - ], - "restart the kernel, then re-run the whole notebook (no confirmation dialog)": [ - "herstart de kernel en voer vervolgens het hele notebook uit (geen bevestigingsdialoogvenster)" - ], - "confirm restart kernel and run all cells": [ - "bevestig herstartern kernel en cellen uitvoeren" - ], - "restart the kernel, then re-run the whole notebook (with dialog)": [ - "herstart de kernel en voer vervolgens het hele notebook uit (met dialoogvenster)" - ], - "restart kernel and clear output": [ - "kernel herstarten en de uitvoer wissen" - ], - "restart the kernel and clear all output (no confirmation dialog)": [ - "herstart de kernel en schakel alle uitvoer uit (geen bevestigingsdialoogvenster)" - ], - "confirm restart kernel and clear output": [ - "bevestigen herstart kernel en verwijder uitvoer" - ], - "restart the kernel and clear all output (with dialog)": [ - "herstart de kernel en verwijder alle uitvoer (met dialoogvenster)" - ], - "interrupt the kernel": [ - "de kernel onderbreken" - ], - "run cell and select next": [ - "cel uitvoeren en volgende selecteren" - ], - "run cell, select below": [ - "cel uitvoeren en de cel eronder selecteren" - ], - "run selected cells": [ - "geselecteerde cellen uitvoeren" - ], - "run cell and insert below": [ - "cel uitvoeren en voeg een cel toe" - ], - "run all cells": [ - "alle cellen uitvoeren" - ], - "run all cells above": [ - "alle cellen erboven uitvoeren" - ], - "run all cells below": [ - "alle cellen eronder uitvoeren" - ], - "enter command mode": [ - "ingaan op de opdrachtmodus" - ], - "insert image": [ - "afbeelding invoegen" - ], - "cut cell attachments": [ - "celbijlagen knippen" - ], - "copy cell attachments": [ - "celbijlagen kopiëren" - ], - "paste cell attachments": [ - "celbijlagen plakken" - ], - "split cell at cursor": [ - "cel splitsen bij cursor" - ], - "enter edit mode": [ - "activeer bewerkingsmodus" - ], - "select previous cell": [ - "vorige cel selecteren" - ], - "select cell above": [ - "cel erboven selecteren" - ], - "select next cell": [ - "volgende cel selecteren" - ], - "select cell below": [ - "cel eronder selecteren" - ], - "extend selection above": [ - "selectie naar boven uitbreiden" - ], - "extend selected cells above": [ - "geselecteerde cellen naar boven uitbreiden" - ], - "extend selection below": [ - "selectie naar onder uitbreiden" - ], - "extend selected cells below": [ - "geselecteerde cellen naar onder uitbreiden" - ], - "cut selected cells": [ - "geselecteerde cellen knippen" - ], - "copy selected cells": [ - "geselecteerde cellen kopiëren" - ], - "paste cells above": [ - "cellen erboven plakken" - ], - "paste cells below": [ - "cellen eronder plakken" - ], - "insert cell above": [ - "cel erboven invoegen" - ], - "insert cell below": [ - "cel eronder invoegen" - ], - "change cell to code": [ - "cel wijzigen naar code" - ], - "change cell to markdown": [ - "cel wijzigen naar markdown" - ], - "change cell to raw": [ - "cel wijzigen naar raw" - ], - "change cell to heading 1": [ - "cel wijzigen naar header 1" - ], - "change cell to heading 2": [ - "cel wijzigen naar header 2" - ], - "change cell to heading 3": [ - "cel wijzigen naar header 3" - ], - "change cell to heading 4": [ - "cel wijzigen naar header 4" - ], - "change cell to heading 5": [ - "cel wijzigen naar header 5" - ], - "change cell to heading 6": [ - "cel wijzigen naar header 6" - ], - "toggle cell output": [ - "celuitvoer in- of uitschakelen" - ], - "toggle output of selected cells": [ - "uitvoer van geselecteerde cellen in- of uitschakelen" - ], - "toggle cell scrolling": [ - "scrollen van cellen in- of uitschakelen" - ], - "toggle output scrolling of selected cells": [ - "scrollen van uitvoer van geselecteerde cellen in- of uitschakelen" - ], - "clear cell output": [ - "verwijder celuitvoer" - ], - "clear output of selected cells": [ - "verwijder uitvoer van geselecteerde cellen" - ], - "move cells down": [ - "cellen naar beneden verplaatsen" - ], - "move selected cells down": [ - "geselecteerde cellen naar beneden verplaatsen" - ], - "move cells up": [ - "cellen omhoog verplaatsen" - ], - "move selected cells up": [ - "geselecteerde cellen omhoog verplaatsen" - ], - "toggle line numbers": [ - "regelnummers in- of uitschakelen" - ], - "show keyboard shortcuts": [ - "sneltoetsen weergeven" - ], - "delete cells": [ - "cellen verwijderen" - ], - "delete selected cells": [ - "geselecteerde cellen verwijderen" - ], - "undo cell deletion": [ - "celverwijdering ongedaan maken" - ], - "merge cell with previous cell": [ - "cel samenvoegen met vorige cel" - ], - "merge cell above": [ - "cel erboven samenvoegen" - ], - "merge cell with next cell": [ - "cel samenvoegen met volgende cel" - ], - "merge cell below": [ - "cel eronder samenvoegen" - ], - "merge selected cells": [ - "geselecteerde cellen samenvoegen" - ], - "merge cells": [ - "cellen samenvoegen" - ], - "merge selected cells, or current cell with cell below if only one cell is selected": [ - "geselecteerde cellen of huidige cel samenvoegen met cel eronder als slechts één cel is geselecteerd" - ], - "show command pallette": [ - "opdrachtpallette weergeven" - ], - "open the command palette": [ - "opdrachtpallette openen" - ], - "toggle all line numbers": [ - "alle regelnummers in- en uitschakelen" - ], - "toggles line numbers in all cells, and persist the setting": [ - "lijnnummers in alle cellen in- of uitschakelen en de instelling aanhouden" - ], - "show all line numbers": [ - "alle regelnummers weergeven" - ], - "show line numbers in all cells, and persist the setting": [ - "lijnnummers in alle cellen weergeven en de instelling aanhouden" - ], - "hide all line numbers": [ - "alle regelnummers verbergen" - ], - "hide line numbers in all cells, and persist the setting": [ - "regelnummers in alle cellen verbergen en de instelling aanhouden" - ], - "toggle header": [ - "koptekst in- en uitschakelen" - ], - "switch between showing and hiding the header": [ - "schakelen tussen het weergeven en verbergen van de koptekst" - ], - "show the header": [ - "de koptekst weergeven" - ], - "hide the header": [ - "de koptekst verbergen" - ], - "toggle toolbar": [ - "werkbalk schakelen" - ], - "switch between showing and hiding the toolbar": [ - "schakelen tussen het weergeven en verbergen van de werkbalk" - ], - "show the toolbar": [ - "de werkbalk weergeven" - ], - "hide the toolbar": [ - "de werkbalk verbergen" - ], - "close the pager": [ - "de pager sluiten" - ], - "ignore": [ - "Negeren" - ], - "move cursor up": [ - "cursor omhoog verplaatsen" - ], - "move cursor down": [ - "cursor omlaag verplaatsen" - ], - "scroll notebook down": [ - "scroll notebook omlaag" - ], - "scroll notebook up": [ - "scroll notebook omhoog" - ], - "scroll cell center": [ - "scroll cel naar het midden" - ], - "Scroll the current cell to the center": [ - "De huidige cel naar het midden scrollen" - ], - "scroll cell top": [ - "scroll cel naar boven" - ], - "Scroll the current cell to the top": [ - "De huidige cel volledig naar boven scrollen" - ], - "duplicate notebook": [ - "dupliceer notebook" - ], - "Create and open a copy of the current notebook": [ - "Een kopie van het huidige notebook maken en openen" - ], - "trust notebook": [ - "vertrouw notebook" - ], - "Trust the current notebook": [ - "Het huidige notebook vertrouwen" - ], - "rename notebook": [ - "naam van notebook wijzigen" - ], - "Rename the current notebook": [ - "De naam van het huidige notebook wijzigen" - ], - "toggle all cells output collapsed": [ - "alle samengevouwen celuitvoer in- of uitschakelen" - ], - "Toggle the hidden state of all output areas": [ - "De zichtbaarheid status van alle uitvoergebieden in- of uitschakelen" - ], - "toggle all cells output scrolled": [ - "alle cellenuitvoer in- of uitschakelen" - ], - "Toggle the scrolling state of all output areas": [ - "De scroll-status van alle uitvoergebieden in- of uitschakelen" - ], - "clear all cells output": [ - "alle cellenuitvoer wissen" - ], - "Clear the content of all the outputs": [ - "De inhoud van alle celuitvoer wissen" - ], - "save notebook": [ - "notebook opslaan" - ], - "Save and Checkpoint": [ - "Opslaan en checkpoint" - ], - "Warning: accessing Cell.cm_config directly is deprecated.": [ - "Waarschuwing: rechtstreeks toegang tot Cell.cm_config wordt afgeschaft." - ], - "Unrecognized cell type: %s": [ - "Niet-herkende celtype: %s" - ], - "Unrecognized cell type": [ - "Niet-herkende celtype" - ], - "Error in cell toolbar callback %s": [ - "Fout in callback-functie van de celwerkbalk" - ], - "Clipboard types: %s": [ - "Klembordtypen: %s" - ], - "Dialog for paste from system clipboard": [ - "Dialoogvenster voor plakken van het klembord van het systeem" - ], - "Ctrl-V": [ - "Ctrl-V" - ], - "Cmd-V": [ - "Cmd-V" - ], - "Press %s again to paste": [ - "Druk nogmaals op %s om te plakken" - ], - "Why is this needed? ": [ - "Waarom is dit nodig? " - ], - "We can't get paste events in this browser without a text box. ": [ - "We kunnen niet plakken in deze browser zonder tekstvak. " - ], - "There's an invisible text box focused in this dialog.": [ - "Er is een onzichtbaar tekstvak geopend in dit dialoogvenster." - ], - "%s to paste": [ - "%s plakken" - ], - "Can't execute cell since kernel is not set.": [ - "Kan geen cel uitvoeren omdat kernel niet is ingesteld." - ], - "In": [ - "In" - ], - "Could not find a kernel matching %s. Please select a kernel:": [ - "Kon geen kernel vinden die overeenkomt met %s. Selecteer een kernel:" - ], - "Continue Without Kernel": [ - "Doorgaan zonder kernel" - ], - "Set Kernel": [ - "Kernel instellen" - ], - "Kernel not found": [ - "Kernel niet gevonden" - ], - "Creating Notebook Failed": [ - "Notebook maken is mislukt" - ], - "The error was: %s": [ - "De fout was: %s" - ], - "Run": [ - "Uitvoeren" - ], - "Code": [ - "Code" - ], - "Markdown": [ - "Markdown" - ], - "Raw NBConvert": [ - "Raw NBConvert" - ], - "Heading": [ - "Headers" - ], - "unrecognized cell type:": [ - "niet-herkende celtype:" - ], - "Failed to retrieve MathJax from '%s'": [ - "Kan MathJax niet ophalen uit '%s'" - ], - "Math/LaTeX rendering will be disabled.": [ - "Wiskunde/LaTeX-rendering wordt uitgeschakeld." - ], - "Trusted Notebook": [ - "Vertrouwd notebook" - ], - "Trust Notebook": [ - "Notebook vertrouwen" - ], - "None": [ - "Geen" - ], - "No checkpoints": [ - "Geen checkpoints" - ], - "Opens in a new window": [ - "Opent in een nieuw venster" - ], - "Autosave in progress, latest changes may be lost.": [ - "Bezig met automatisch opslaan, de laatste wijzigingen kunnen verloren gaan." - ], - "Unsaved changes will be lost.": [ - "Niet-opgeslagen wijzigingen gaan verloren." - ], - "The Kernel is busy, outputs may be lost.": [ - "De Kernel is bezet, uitvoeren kunnen verloren gaan." - ], - "This notebook is version %1$s, but we only fully support up to %2$s.": [ - "Deze notebook is versie %1$s, maar we ondersteunen alleen volledig tot %2$s." - ], - "You can still work with this notebook, but cell and output types introduced in later notebook versions will not be available.": [ - "U kunt nog steeds met deze notebook werken, maar cel- en uitvoertypen die in latere notebookversies zijn geïntroduceerd, zijn niet beschikbaar." - ], - "Restart and Run All Cells": [ - "Herstarten en alle cellen uitvoeren" - ], - "Restart and Clear All Outputs": [ - "Herstarten en alle uitvoer wissen" - ], - "Restart": [ - "Herstarten" - ], - "Continue Running": [ - "Doorgaan met uitvoeren" - ], - "Reload": [ - "Reload" - ], - "Overwrite": [ - "Overschrijven" - ], - "Trust": [ - "Vertrouwen" - ], - "Revert": [ - "Terugkeren" - ], - "Newer Notebook": [ - "Nieuwer notebook" - ], - "Use markdown headings": [ - "Markdown headers gebruiken" - ], - "Jupyter no longer uses special heading cells. Instead, write your headings in Markdown cells using # characters:": [ - "Jupyter maakt geen gebruik meer van speciale headercellen. Schrijf in plaats daarvan uw headers in Markdown-cellen met # tekens:" - ], - "## This is a level 2 heading": [ - "## Dit is een niveau 2 header" - ], - "Restart kernel and re-run the whole notebook?": [ - "Kernel herstarten en het hele notebook opnieuw uitvoeren?" - ], - "Are you sure you want to restart the current kernel and re-execute the whole notebook? All variables and outputs will be lost.": [ - "Weet u zeker dat u de huidige kernel wilt herstarten en het hele notebook opnieuw wilt uitvoeren? Alle variabelen en uitgangen gaan verloren." - ], - "Restart kernel and clear all output?": [ - "Herstart kernel en verwijder alle output?" - ], - "Do you want to restart the current kernel and clear all output? All variables and outputs will be lost.": [ - "Wilt u de huidige kernel herstarten en alle uitvoer wissen? Alle variabelen en uitgangen gaan verloren." - ], - "Restart kernel?": [ - "Kernel herstarten?" - ], - "Do you want to restart the current kernel? All variables will be lost.": [ - "Wilt u de huidige kernel herstarten? Alle variabelen gaan verloren." - ], - "Shutdown kernel?": [ - "Kernel afsluiten?" - ], - "Do you want to shutdown the current kernel? All variables will be lost.": [ - "Wilt u de huidige kernel afsluiten? Alle variabelen gaan verloren." - ], - "Notebook changed": [ - "Notebook gewijzigd" - ], - "The notebook file has changed on disk since the last time we opened or saved it. Do you want to overwrite the file on disk with the version open here, or load the version on disk (reload the page) ?": [ - "Het notebookbestand op de schijf is gewijzigd sinds de laatste keer dat het geopend of opgeslagen is. Wilt u het bestand op schijf overschrijven met de versie die hier wordt geopend, of de versie op schijf laden (de pagina opnieuw laden) ?" - ], - "Notebook validation failed": [ - "Notebook validatie is mislukt" - ], - "The save operation succeeded, but the notebook does not appear to be valid. The validation error was:": [ - "De opslagbewerking is geslaagd, maar het notebook lijkt niet geldig te zijn. De validatiefout was:" - ], - "A trusted Jupyter notebook may execute hidden malicious code when you open it. Selecting trust will immediately reload this notebook in a trusted state. For more information, see the Jupyter security documentation: ": [ - "Een vertrouwd Jupyter-notebook kan verborgen schadelijke code uitvoeren wanneer u het opent. Als u vertrouwensstatus selecteert, wordt dit notebook onmiddellijk opnieuw geladen in een vertrouwde status. Zie voor meer informatie de beveiligingsdocumentatie van Jupyter: " - ], - "here": [ - "hier" - ], - "Trust this notebook?": [ - "Vertrouw je dit notebook?" - ], - "Notebook failed to load": [ - "Notebook kan niet worden geladen" - ], - "The error was: ": [ - "De fout was: " - ], - "See the error console for details.": [ - "Zie de foutconsole voor meer informatie." - ], - "The notebook also failed validation:": [ - "De notebook validatie is ook mislukt:" - ], - "An invalid notebook may not function properly. The validation error was:": [ - "Een ongeldig notebook werkt mogelijk niet goed. De validatiefout was:" - ], - "This notebook has been converted from an older notebook format to the current notebook format v(%s).": [ - "Deze notebook is geconverteerd van een oudere notebookindeling naar de huidige notebookindeling v(%s)." - ], - "This notebook has been converted from a newer notebook format to the current notebook format v(%s).": [ - "Deze notebook is geconverteerd van een nieuwere notebookindeling naar de huidige notebookindeling v(%s)." - ], - "The next time you save this notebook, the current notebook format will be used.": [ - "De volgende keer dat u dit notebook opslaat, wordt de huidige notebookindeling gebruikt." - ], - "Older versions of Jupyter may not be able to read the new format.": [ - "Oudere versies van Jupyter kunnen het nieuwe formaat mogelijk niet lezen." - ], - "Some features of the original notebook may not be available.": [ - "Sommige functies van de originele notebook zijn mogelijk niet beschikbaar." - ], - "To preserve the original version, close the notebook without saving it.": [ - "Als u de oorspronkelijke versie wilt behouden, sluit u het notebook zonder deze op te slaan." - ], - "Notebook converted": [ - "Notebook geconverteerd" - ], - "(No name)": [ - "(Geen naam)" - ], - "An unknown error occurred while loading this notebook. This version can load notebook formats %s or earlier. See the server log for details.": [ - "Er is een onbekende fout opgetreden tijdens het laden van dit notebook. Deze versie kan notebook-indelingen %s of eerder laden. Zie het serverlogboek voor meer informatie." - ], - "Error loading notebook": [ - "Fout bij het laden van notebook" - ], - "Are you sure you want to revert the notebook to the latest checkpoint?": [ - "Weet je zeker dat je het notebook wilt terugdraaien naar het laatste checkpoint?" - ], - "This cannot be undone.": [ - "Dit kan niet ongedaan worden gemaakt." - ], - "The checkpoint was last updated at:": [ - "Het checkpoint is voor het laatst bijgewerkt op:" - ], - "Revert notebook to checkpoint": [ - "Notebook terugzetten naar checkpoint" - ], - "Edit Mode": [ - "Bewerkingsmodus" - ], - "Command Mode": [ - "Opdrachtmodus" - ], - "Kernel Created": [ - "Kernel aangemaakt" - ], - "Connecting to kernel": [ - "Verbinding maken met kernel" - ], - "Not Connected": [ - "Niet verbonden" - ], - "click to reconnect": [ - "klik om opnieuw verbinding te maken" - ], - "Restarting kernel": [ - "Kernel herstarten" - ], - "Kernel Restarting": [ - "Kernel herstarten" - ], - "The kernel appears to have died. It will restart automatically.": [ - "De kernel lijkt te zijn gestopt. Hij wordt automatisch herstart." - ], - "Dead kernel": [ - "Gestopte kernel" - ], - "Kernel Dead": [ - "Kernel is gestopt" - ], - "Interrupting kernel": [ - "Kernel onderbreken" - ], - "No Connection to Kernel": [ - "Geen verbinding met kernel" - ], - "A connection to the notebook server could not be established. The notebook will continue trying to reconnect. Check your network connection or notebook server configuration.": [ - "Er kan geen verbinding met de notebookserver worden gemaakt. Het notebook blijft proberen opnieuw verbinding te maken. Controleer de configuratie van uw netwerkverbinding of laptopserver." - ], - "Connection failed": [ - "Verbinding is mislukt" - ], - "No kernel": [ - "Geen kernel" - ], - "Kernel is not running": [ - "Kernel is niet actief" - ], - "Don't Restart": [ - "Niet herstarten" - ], - "Try Restarting Now": [ - "Probeer nu te herstarten" - ], - "The kernel has died, and the automatic restart has failed. It is possible the kernel cannot be restarted. If you are not able to restart the kernel, you will still be able to save the notebook, but running code will no longer work until the notebook is reopened.": [ - "De kernel is gestopt en de automatische herstart is mislukt. Het is mogelijk dat de kernel niet kan worden herstart. Als u de kernel niet start, kan u het notebook nog steeds opslaan, maar werkt de code niet meer totdat het notebook opnieuw is geopend." - ], - "No Kernel": [ - "Geen kernel" - ], - "Failed to start the kernel": [ - "Kan de kernel niet starten" - ], - "Kernel Busy": [ - "Kernel bezet" - ], - "Kernel starting, please wait...": [ - "Kernel beginnen, wachten..." - ], - "Kernel Idle": [ - "Kernel Idle" - ], - "Kernel ready": [ - "Kernel klaar" - ], - "Using kernel: ": [ - "Kernel gebruiken: " - ], - "Only candidate for language: %1$s was %2$s.": [ - "Enige kandidaat voor taal: %1$s was %2$s." - ], - "Loading notebook": [ - "Notebook laden" - ], - "Notebook loaded": [ - "Notebook geladen" - ], - "Saving notebook": [ - "Notebook opslaan" - ], - "Notebook saved": [ - "Notebook opgeslagen" - ], - "Notebook save failed": [ - "Notebook opslaan is mislukt" - ], - "Notebook copy failed": [ - "Notebook kopiëren is mislukt" - ], - "Checkpoint created": [ - "Checkpoint gemaakt" - ], - "Checkpoint failed": [ - "Checkpoint is mislukt" - ], - "Checkpoint deleted": [ - "Checkpoint verwijderd" - ], - "Checkpoint delete failed": [ - "Checkpoint verwijderen is mislukt" - ], - "Restoring to checkpoint...": [ - "Herstellen naar checkpoint..." - ], - "Checkpoint restore failed": [ - "Checkpoint herstel is mislukt" - ], - "Autosave disabled": [ - "Automatisch opslaan uitgeschakeld" - ], - "Saving every %d sec.": [ - "Het notebook wordt elke %d sec opgeslagen." - ], - "Trusted": [ - "Vertrouwd" - ], - "Not Trusted": [ - "Niet vertrouwd" - ], - "click to expand output": [ - "klik om de uitvoer volledig weer te geven" - ], - "click to expand output; double click to hide output": [ - "klik om de uitvoer te laten verschijnen; dubbelklikken om uitvoer te verbergen" - ], - "click to unscroll output; double click to hide": [ - "klik om de uitvoer te ontscrollen; dubbelklikken om te verbergen" - ], - "click to scroll output; double click to hide": [ - "klik om de uitvoer te scrollen; dubbelklikken om te verbergen" - ], - "Javascript error adding output!": [ - "Javascript fout bij het toevoegen van uitvoer!" - ], - "See your browser Javascript console for more details.": [ - "Zie uw browser Javascript console voor meer details." - ], - "Out[%d]:": [ - "Out[%d]:" - ], - "Unrecognized output: %s": [ - "Niet-herkende uitvoer: %s" - ], - "Open the pager in an external window": [ - "De pager openen in een extern venster" - ], - "Close the pager": [ - "De pager sluiten" - ], - "Jupyter Pager": [ - "Jupyter Pager" - ], - "go to cell start": [ - "ga naar celstart" - ], - "go to cell end": [ - "ga naar het celeinde" - ], - "go one word left": [ - "één woord naar links gaan" - ], - "go one word right": [ - "ga een woord naar rechts" - ], - "delete word before": [ - "woord ervoor verwijderen" - ], - "delete word after": [ - "woord erna verwijderen" - ], - "code completion or indent": [ - "code aanvulling of inspringing" - ], - "tooltip": [ - "Tooltip" - ], - "indent": [ - "inspringing" - ], - "dedent": [ - "inspringing ongedaan maken" - ], - "select all": [ - "selecteer alle" - ], - "undo": [ - "Ongedaan maken" - ], - "redo": [ - "Opnieuw" - ], - "Shift": [ - "Shift" - ], - "Alt": [ - "Alt" - ], - "Up": [ - "Omhoog" - ], - "Down": [ - "Omlaag" - ], - "Left": [ - "Links" - ], - "Right": [ - "Recht" - ], - "Tab": [ - "Tab" - ], - "Caps Lock": [ - "CAPS-LOCK" - ], - "Esc": [ - "Esc" - ], - "Ctrl": [ - "Ctrl" - ], - "Enter": [ - "Enter" - ], - "Page Up": [ - "Pagina omhoog" - ], - "Page Down": [ - "Pagina omlaag" - ], - "Home": [ - "Home" - ], - "End": [ - "Einde" - ], - "Space": [ - "Spatie" - ], - "Backspace": [ - "Backspace" - ], - "Minus": [ - "Minus" - ], - "PageUp": [ - "PageUp" - ], - "The Jupyter Notebook has two different keyboard input modes.": [ - "De Jupyter Notebook heeft twee verschillende toetsenbordinvoermodi." - ], - "Edit mode allows you to type code or text into a cell and is indicated by a green cell border.": [ - "Edit-modus u code of tekst typen in een cel en wordt aangegeven door een groene celrand." - ], - "Command mode binds the keyboard to notebook level commands and is indicated by a grey cell border with a blue left margin.": [ - "Command-modus het toetsenbord bindt aan opdrachten op notebookniveau en wordt aangegeven door een grijze celrand met een blauwe linkermarge." - ], - "Close": [ - "Sluiten" - ], - "Keyboard shortcuts": [ - "Sneltoetsen" - ], - "Command": [ - "Opdracht" - ], - "Control": [ - "Controle" - ], - "Option": [ - "Optie" - ], - "Return": [ - "Terug" - ], - "Command Mode (press %s to enable)": [ - "Opdrachtmodus (druk op %s om in te schakelen)" - ], - "Edit Shortcuts": [ - "Sneltoetsen bewerken" - ], - "edit command-mode keyboard shortcuts": [ - "Sneltoetsen in de opdrachtmodus bewerken" - ], - "Edit Mode (press %s to enable)": [ - "Bewerkingsmodus (druk op %s om in te schakelen)" - ], - "Autosave Failed!": [ - "Automatisch opslaan is mislukt!" - ], - "Rename": [ - "Hernoemen" - ], - "Enter a new notebook name:": [ - "Voer een nieuwe notebooknaam in:" - ], - "Rename Notebook": [ - "De naam van notebook wijzigen" - ], - "Invalid notebook name. Notebook names must have 1 or more characters and can contain any characters except :/\\. Please enter a new notebook name:": [ - "Ongeldige notebooknaam. Notebook-namen moeten 1 of meer tekens bevatten en kunnen tekens bevatten, behalve :/\\. Voer een nieuwe notebooknaam in:" - ], - "Renaming...": [ - "Hernoemen..." - ], - "Unknown error": [ - "Onbekende fout" - ], - "no checkpoint": [ - "geen checkpoint" - ], - "Last Checkpoint: %s": [ - "Laatste checkpoint: %s" - ], - "(unsaved changes)": [ - "(niet-opgeslagen wijzigingen)" - ], - "(autosaved)": [ - "(automatisch opgeslagen)" - ], - "Warning: too many matches (%d). Some changes might not be shown or applied.": [ - "Waarschuwing: te veel matches (%d). Sommige wijzigingen worden mogelijk niet weergegeven of toegepast." - ], - "%d match": [ - "%d match", - "%d matches" - ], - "More than 100 matches, aborting": [ - "Meer dan 100 matches, afbreken" - ], - "Use regex (JavaScript regex syntax)": [ - "Regex gebruiken (JavaScript regex syntax)" - ], - "Replace in selected cells": [ - "Vervangen in geselecteerde cellen" - ], - "Match case": [ - "Hoofdletters matchen" - ], - "Find": [ - "Zoek" - ], - "Replace": [ - "Vervangen" - ], - "No matches, invalid or empty regular expression": [ - "Geen overeenkomsten, ongeldige of lege reguliere expressie" - ], - "Replace All": [ - "Alles vervangen" - ], - "Find and Replace": [ - "Zoeken en vervangen" - ], - "find and replace": [ - "zoeken en vervangen" - ], - "Write raw LaTeX or other formats here, for use with nbconvert. It will not be rendered in the notebook. When passing through nbconvert, a Raw Cell's content is added to the output unmodified.": [ - "Schrijf hier in LaTeX of ander format, voor gebruik met nbconvert. Het wordt niet weergegeven in het notebook. Bij het doorlopen van nbconvert wordt de inhoud van een Raw Cell ongewijzigd aan de uitvoer toegevoegd." - ], - "Grow the tooltip vertically (press shift-tab twice)": [ - "De tooltip verticaal laten groeien (druk twee keer op shift-tab)" - ], - "show the current docstring in pager (press shift-tab 4 times)": [ - "de huidige docstring weergeven in pager (druk 4 keer op shift-tab)" - ], - "Open in Pager": [ - "Openen in Pager" - ], - "Tooltip will linger for 10 seconds while you type": [ - "De tooltip blijft 10 seconden hangen terwijl u typt" - ], - "Welcome to the Notebook Tour": [ - "Welkom bij de Notebook Rondleiding" - ], - "You can use the left and right arrow keys to go backwards and forwards.": [ - "U kan de pijltjestoetsen links en rechts gebruiken om heen en weer te gaan." - ], - "Filename": [ - "Bestandsnaam" - ], - "Click here to change the filename for this notebook.": [ - "Klik hier om de bestandsnaam voor dit notebook te wijzigen." - ], - "Notebook Menubar": [ - "Menubalk notebook" - ], - "The menubar has menus for actions on the notebook, its cells, and the kernel it communicates with.": [ - "De menubalk heeft menu's voor acties op het notebook, de cellen en de kernel waarmee het communiceert." - ], - "Notebook Toolbar": [ - "Werkbalk Notebook" - ], - "The toolbar has buttons for the most common actions. Hover your mouse over each button for more information.": [ - "De werkbalk heeft knoppen voor de meest voorkomende acties. Beweeg met je muis over elke knop voor meer informatie." - ], - "Mode Indicator": [ - "Modus-indicator" - ], - "The Notebook has two modes: Edit Mode and Command Mode. In this area, an indicator can appear to tell you which mode you are in.": [ - "De notebook heeft twee modi: De modus bewerken en de opdrachtmodus. In dit gebied kan een indicator verschijnen om u te vertellen in welke modus u zich bevindt." - ], - "Right now you are in Command Mode, and many keyboard shortcuts are available. In this mode, no icon is displayed in the indicator area.": [ - "Op dit moment bent u in de opdrachtmodus en zijn er veel sneltoetsen beschikbaar. In deze modus wordt geen pictogram weergegeven in het indicatorgebied." - ], - "Pressing Enter or clicking in the input text area of the cell switches to Edit Mode.": [ - "Als u op Enter drukt of klikt in het invoertekstgebied van de cel, schakelt u over naar de bewerkingsmodus." - ], - "Notice that the border around the currently active cell changed color. Typing will insert text into the currently active cell.": [ - "De rand rond de actieve cel is van kleur veranderd. Als u typt, wordt tekst ingevoegd in de actieve cel." - ], - "Back to Command Mode": [ - "Terug naar de opdrachtmodus" - ], - "Pressing Esc or clicking outside of the input text area takes you back to Command Mode.": [ - "Als u op Esc drukt of buiten het invoertekstgebied klikt, gaat u terug naar de opdrachtmodus." - ], - "Keyboard Shortcuts": [ - "Sneltoetsen" - ], - "You can click here to get a list of all of the keyboard shortcuts.": [ - "U hier klikken om een lijst van alle sneltoetsen te krijgen." - ], - "Kernel Indicator": [ - "Kernel Indicator" - ], - "This is the Kernel indicator. It looks like this when the Kernel is idle.": [ - "Dit is de Kernel indicator. Het ziet er zo uit als de Kernel niet actief is." - ], - "The Kernel indicator looks like this when the Kernel is busy.": [ - "De Kernel indicator ziet er als volgt uit wanneer de Kernel bezig is." - ], - "Interrupting the Kernel": [ - "De kernel onderbreken" - ], - "To cancel a computation in progress, you can click here.": [ - "Als u een actieve berekening wilt annuleren, kan u hier klikken." - ], - "Notification Area": [ - "Systeemvak" - ], - "Messages in response to user actions (Save, Interrupt, etc.) appear here.": [ - "Berichten in reactie op acties van gebruikers (Opslaan, Onderbreken, enz.) worden hier weergegeven." - ], - "End of Tour": [ - "Einde van de Tour" - ], - "This concludes the Jupyter Notebook User Interface Tour.": [ - "Dit concludeert de Jupyter Notebook User Interface Rondleiding." - ], - "Edit Attachments": [ - "Bijlagen bewerken" - ], - "Cell": [ - "Cel" - ], - "Edit Metadata": [ - "Metagegevens bewerken" - ], - "Custom": [ - "Aangepaste" - ], - "Set the MIME type of the raw cell:": [ - "Stel het MIME-type van de raw cel in:" - ], - "Raw Cell MIME Type": [ - "Raw Cell MIME-type" - ], - "Raw NBConvert Format": [ - "Raw NBConvert-indeling" - ], - "Raw Cell Format": [ - "Raw-celnotatie" - ], - "Slide": [ - "Dia" - ], - "Sub-Slide": [ - "Subdia" - ], - "Fragment": [ - "Fragment" - ], - "Skip": [ - "Overslaan" - ], - "Notes": [ - "Notities" - ], - "Slide Type": [ - "Diatype" - ], - "Slideshow": [ - "Diavoorstelling" - ], - "Add tag": [ - "Tag toevoegen" - ], - "Edit the list of tags below. All whitespace is treated as tag separators.": [ - "Bewerk de onderstaande lijst met tags. Alle witruimte wordt behandeld als tagscheidingstekens." - ], - "Edit the tags": [ - "De tags bewerken" - ], - "Edit Tags": [ - "Tags bewerken" - ], - "Shutdown": [ - "Afsluiten" - ], - "Create a new notebook with %s": [ - "Een nieuw notebook maken met %s" - ], - "An error occurred while creating a new notebook.": [ - "Er is een fout opgetreden tijdens het maken van een nieuw notebook." - ], - "Creating File Failed": [ - "Bestand maken is mislukt" - ], - "An error occurred while creating a new file.": [ - "Er is een fout opgetreden tijdens het maken van een nieuw bestand." - ], - "Creating Folder Failed": [ - "Map maken is mislukt" - ], - "An error occurred while creating a new folder.": [ - "Er is een fout opgetreden tijdens het maken van een nieuwe map." - ], - "Failed to read file": [ - "Bestand niet kunnen worden gelezen" - ], - "Failed to read file %s": [ - "Bestand %s niet kunnen lezen" - ], - "The file size is %d MB. Do you still want to upload it?": [ - "De bestandsgrootte is %d MB. Wil je het nog steeds uploaden?" - ], - "Large file size warning": [ - "Waarschuwing voor grote bestandsgrootte" - ], - "Server error: ": [ - "Serverfout: " - ], - "The notebook list is empty.": [ - "De lijst met notebooks is leeg." - ], - "Click here to rename, delete, etc.": [ - "Klik hier om de naam te wijzigen, te verwijderen, enz." - ], - "Running": [ - "Actieve Processen" - ], - "Enter a new file name:": [ - "Voer een nieuwe bestandsnaam in:" - ], - "Enter a new directory name:": [ - "Voer een nieuwe mapnaam in:" - ], - "Enter a new name:": [ - "Voer een nieuwe naam in:" - ], - "Rename file": [ - "Naamvan het bestand wijzigen" - ], - "Rename directory": [ - "Naamvan naam wijzigen" - ], - "Rename notebook": [ - "De naam van notebook wijzigen" - ], - "Move": [ - "Verplaatsen" - ], - "An error occurred while renaming \"%1$s\" to \"%2$s\".": [ - "Er is een fout opgetreden bij het hernoemen van \"%1$s\" naar \"%2$s\"." - ], - "Rename Failed": [ - "Naam wijzigen Van mislukt" - ], - "Enter a new destination directory path for this item:": [ - "Voer een nieuw bestemmingsmap-pad in voor dit item:", - "Voer een nieuw bestemmingsmap-pad in voor deze %d items:" - ], - "Move an Item": [ - "Een item verplaatsen", - "%d objecten verplaatsen" - ], - "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\".": [ - "Er is een fout opgetreden tijdens het verplaatsen van \"%1$s\" van \"%2$s\" naar \"%3$s\"." - ], - "Move Failed": [ - "Verplaatsen mislukt" - ], - "Are you sure you want to permanently delete: \"%s\"?": [ - "Weet u zeker dat u het volgende definitief wilt verwijderen: \"%s\"?", - "Weet u zeker dat u de geselecteerde %d bestanden of mappen permanent wilt verwijderen?" - ], - "An error occurred while deleting \"%s\".": [ - "Er is een fout opgetreden tijdens het verwijderen van \"%s\"." - ], - "Delete Failed": [ - "Verwijderen mislukt" - ], - "Are you sure you want to duplicate: \"%s\"?": [ - "Weet u zeker dat u wilt dupliceren: \"%s\"?", - "Weet u zeker dat u de geselecteerde %d bestanden wilt dupliceren?" - ], - "Duplicate": [ - "Dupliceren" - ], - "An error occurred while duplicating \"%s\".": [ - "Er is een fout opgetreden tijdens het dupliceren van \"%s\"." - ], - "Duplicate Failed": [ - "Dupliceren is mislukt" - ], - "Upload": [ - "Uploaden" - ], - "Invalid file name": [ - "Ongeldige bestandsnaam" - ], - "File names must be at least one character and not start with a period": [ - "Bestandsnamen moeten ten minste één teken zijn en niet beginnen met een periode" - ], - "Cannot upload invalid Notebook": [ - "Kan ongeldig notebook niet uploaden" - ], - "There is already a file named \"%s\". Do you want to replace it?": [ - "Er is al een bestand met de naam \"%s\". Wilt u het vervangen?" - ], - "Replace file": [ - "Bestand vervangen" - ] - } - } -} \ No newline at end of file diff --git a/notebook/i18n/nl/LC_MESSAGES/nbjs.po b/notebook/i18n/nl/LC_MESSAGES/nbjs.po deleted file mode 100644 index c091c0212..000000000 --- a/notebook/i18n/nl/LC_MESSAGES/nbjs.po +++ /dev/null @@ -1,2116 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-06-27 14:04-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/static/base/js/dialog.js:161 -msgid "Manually edit the JSON below to manipulate the metadata for this cell." -msgstr "" -"Bewerk de JSON eronder handmatig om de metagegevens voor deze cel te " -"manipuleren." - -#: notebook/static/base/js/dialog.js:163 -msgid "" -"Manually edit the JSON below to manipulate the metadata for this notebook." -msgstr "" -"Bewerk de JSON eronder handmatig om de metagegevens voor dit notebook " -"te manipuleren." - -#: notebook/static/base/js/dialog.js:165 -msgid "" -" We recommend putting custom metadata attributes in an appropriately named " -"substructure, so they don't conflict with those of others." -msgstr "" -" We raden u aan aangepaste metagegevenskenmerken in een op de juiste naam " -"genoemde substructuur te plaatsen, zodat ze niet in strijd zijn met die van " -"anderen." - -#: notebook/static/base/js/dialog.js:180 -msgid "Edit the metadata" -msgstr "De metagegevens bewerken" - -#: notebook/static/base/js/dialog.js:202 -msgid "Edit Notebook Metadata" -msgstr "Metagegevens van notebook bewerken" - -#: notebook/static/base/js/dialog.js:204 -msgid "Edit Cell Metadata" -msgstr "Celmetagegevens bewerken" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/notebook.js:475 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:859 -#: notebook/static/tree/js/notebooklist.js:1418 -msgid "Cancel" -msgstr "Annuleren" - -#: notebook/static/base/js/dialog.js:208 -msgid "Edit" -msgstr "Bewerken" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/kernelselector.js:278 -#: notebook/static/notebook/js/mathjaxutils.js:42 -#: notebook/static/notebook/js/notebook.js:469 -#: notebook/static/notebook/js/notificationarea.js:187 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/newnotebook.js:97 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "OK" -msgstr "OK" - -#: notebook/static/base/js/dialog.js:208 -msgid "Apply" -msgstr "Toepassen" - -#: notebook/static/base/js/dialog.js:225 -msgid "WARNING: Could not save invalid JSON." -msgstr "WAARSCHUWING: Kan ongeldige JSON niet opslaan." - -#: notebook/static/base/js/dialog.js:247 -msgid "There are no attachments for this cell." -msgstr "Er zijn geen bijlagen voor deze cel." - -#: notebook/static/base/js/dialog.js:250 -msgid "Current cell attachments" -msgstr "Huidige celbijlagen" - -#: notebook/static/base/js/dialog.js:259 -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:46 -msgid "Attachments" -msgstr "Bijlagen" - -#: notebook/static/base/js/dialog.js:283 -msgid "Restore" -msgstr "Herstellen" - -#: notebook/static/base/js/dialog.js:293 -#: notebook/static/tree/js/notebooklist.js:1018 -msgid "Delete" -msgstr "Verwijderen" - -#: notebook/static/base/js/dialog.js:342 notebook/static/base/js/dialog.js:386 -msgid "Edit attachments" -msgstr "Bijlagen bewerken" - -#: notebook/static/base/js/dialog.js:348 -msgid "Edit Notebook Attachments" -msgstr "Notebook-bijlagen bewerken" - -#: notebook/static/base/js/dialog.js:350 -msgid "Edit Cell Attachments" -msgstr "Celbijlagen bewerken" - -#: notebook/static/base/js/dialog.js:373 -msgid "Select a file to insert." -msgstr "Selecteer een bestand dat u wilt invoegen." - -#: notebook/static/base/js/dialog.js:399 -msgid "Select a file" -msgstr "Een bestand selecteren" - -#: notebook/static/notebook/js/about.js:14 -msgid "You are using Jupyter notebook." -msgstr "U gebruikt Jupyter notebook." - -#: notebook/static/notebook/js/about.js:16 -msgid "The version of the notebook server is: " -msgstr "De versie van de notebookserver is: " - -#: notebook/static/notebook/js/about.js:22 -msgid "The server is running on this version of Python:" -msgstr "De server draait op deze versie van Python:" - -#: notebook/static/notebook/js/about.js:25 -msgid "Waiting for kernel to be available..." -msgstr "Wachten tot kernel beschikbaar is..." - -#: notebook/static/notebook/js/about.js:27 -msgid "Server Information:" -msgstr "Servergegevens:" - -#: notebook/static/notebook/js/about.js:29 -msgid "Current Kernel Information:" -msgstr "Informatie van huidige kernel:" - -#: notebook/static/notebook/js/about.js:32 -msgid "Could not access sys_info variable for version information." -msgstr "" -"Kon geen toegang krijgen tot sys_info variabele voor versie-informatie." - -#: notebook/static/notebook/js/about.js:34 -msgid "Cannot find sys_info!" -msgstr "Ik kan sys_info niet vinden!" - -#: notebook/static/notebook/js/about.js:38 -msgid "About Jupyter Notebook" -msgstr "Over Jupyter Notebook" - -#: notebook/static/notebook/js/about.js:47 -msgid "unable to contact kernel" -msgstr "kan de kernel niet bereiken" - -#: notebook/static/notebook/js/actions.js:69 -msgid "toggle rtl layout" -msgstr "rtl-indeling in- en uitschakelen" - -#: notebook/static/notebook/js/actions.js:70 -msgid "" -"Toggle the screen directionality between left-to-right and right-to-left" -msgstr "" -"De richting van het scherm schakelen tussen links-naar-rechts en rechts-" -"naar-links" - -#: notebook/static/notebook/js/actions.js:76 -msgid "edit command mode keyboard shortcuts" -msgstr "sneltoetsen in de opdrachtmodus bewerken" - -#: notebook/static/notebook/js/actions.js:77 -msgid "Open a dialog to edit the command mode keyboard shortcuts" -msgstr "" -"Een dialoogvenster openen om sneltoetsen in de opdrachtmodus te bewerken" - -#: notebook/static/notebook/js/actions.js:97 -msgid "restart kernel" -msgstr "kernel herstarten" - -#: notebook/static/notebook/js/actions.js:98 -msgid "restart the kernel (no confirmation dialog)" -msgstr "de kernel herstarten (geen bevestigingsdialoogvenster)" - -#: notebook/static/notebook/js/actions.js:106 -msgid "confirm restart kernel" -msgstr "bevestig herstart van kernel" - -#: notebook/static/notebook/js/actions.js:107 -msgid "restart the kernel (with dialog)" -msgstr "de kernel herstarten (met dialoogvenster)" - -#: notebook/static/notebook/js/actions.js:113 -msgid "restart kernel and run all cells" -msgstr "kernel herstarten en alle cellen uitvoeren" - -#: notebook/static/notebook/js/actions.js:114 -msgid "" -"restart the kernel, then re-run the whole notebook (no confirmation dialog)" -msgstr "" -"herstart de kernel en voer vervolgens het hele notebook uit " -"(geen bevestigingsdialoogvenster)" - -#: notebook/static/notebook/js/actions.js:120 -msgid "confirm restart kernel and run all cells" -msgstr "bevestig herstartern kernel en cellen uitvoeren" - -#: notebook/static/notebook/js/actions.js:121 -msgid "restart the kernel, then re-run the whole notebook (with dialog)" -msgstr "" -"herstart de kernel en voer vervolgens het hele notebook uit " -"(met dialoogvenster)" - -#: notebook/static/notebook/js/actions.js:127 -msgid "restart kernel and clear output" -msgstr "kernel herstarten en de uitvoer wissen" - -#: notebook/static/notebook/js/actions.js:128 -msgid "restart the kernel and clear all output (no confirmation dialog)" -msgstr "" -"herstart de kernel en schakel alle uitvoer uit (geen " -"bevestigingsdialoogvenster)" - -#: notebook/static/notebook/js/actions.js:134 -msgid "confirm restart kernel and clear output" -msgstr "bevestigen herstart kernel en verwijder uitvoer" - -#: notebook/static/notebook/js/actions.js:135 -msgid "restart the kernel and clear all output (with dialog)" -msgstr "" -"herstart de kernel en verwijder alle uitvoer (met dialoogvenster)" - -#: notebook/static/notebook/js/actions.js:142 -#: notebook/static/notebook/js/actions.js:143 -msgid "interrupt the kernel" -msgstr "de kernel onderbreken" - -#: notebook/static/notebook/js/actions.js:150 -msgid "run cell and select next" -msgstr "cel uitvoeren en volgende selecteren" - -#: notebook/static/notebook/js/actions.js:152 -msgid "run cell, select below" -msgstr "cel uitvoeren en de cel eronder selecteren" - -#: notebook/static/notebook/js/actions.js:159 -#: notebook/static/notebook/js/actions.js:160 -msgid "run selected cells" -msgstr "geselecteerde cellen uitvoeren" - -#: notebook/static/notebook/js/actions.js:167 -#: notebook/static/notebook/js/actions.js:168 -msgid "run cell and insert below" -msgstr "cel uitvoeren en voeg een cel toe" - -#: notebook/static/notebook/js/actions.js:175 -#: notebook/static/notebook/js/actions.js:176 -msgid "run all cells" -msgstr "alle cellen uitvoeren" - -#: notebook/static/notebook/js/actions.js:183 -#: notebook/static/notebook/js/actions.js:184 -msgid "run all cells above" -msgstr "alle cellen erboven uitvoeren" - -#: notebook/static/notebook/js/actions.js:190 -#: notebook/static/notebook/js/actions.js:191 -msgid "run all cells below" -msgstr "alle cellen eronder uitvoeren" - -#: notebook/static/notebook/js/actions.js:197 -#: notebook/static/notebook/js/actions.js:198 -msgid "enter command mode" -msgstr "ingaan op de opdrachtmodus" - -#: notebook/static/notebook/js/actions.js:205 -#: notebook/static/notebook/js/actions.js:206 -msgid "insert image" -msgstr "afbeelding invoegen" - -#: notebook/static/notebook/js/actions.js:213 -#: notebook/static/notebook/js/actions.js:214 -msgid "cut cell attachments" -msgstr "celbijlagen knippen" - -#: notebook/static/notebook/js/actions.js:221 -#: notebook/static/notebook/js/actions.js:222 -msgid "copy cell attachments" -msgstr "celbijlagen kopiëren" - -#: notebook/static/notebook/js/actions.js:229 -#: notebook/static/notebook/js/actions.js:230 -msgid "paste cell attachments" -msgstr "celbijlagen plakken" - -#: notebook/static/notebook/js/actions.js:237 -#: notebook/static/notebook/js/actions.js:238 -msgid "split cell at cursor" -msgstr "cel splitsen bij cursor" - -#: notebook/static/notebook/js/actions.js:245 -#: notebook/static/notebook/js/actions.js:246 -msgid "enter edit mode" -msgstr "activeer bewerkingsmodus" - -#: notebook/static/notebook/js/actions.js:253 -msgid "select previous cell" -msgstr "vorige cel selecteren" - -#: notebook/static/notebook/js/actions.js:254 -msgid "select cell above" -msgstr "cel erboven selecteren" - -#: notebook/static/notebook/js/actions.js:265 -msgid "select next cell" -msgstr "volgende cel selecteren" - -#: notebook/static/notebook/js/actions.js:266 -msgid "select cell below" -msgstr "cel eronder selecteren" - -#: notebook/static/notebook/js/actions.js:277 -msgid "extend selection above" -msgstr "selectie naar boven uitbreiden" - -#: notebook/static/notebook/js/actions.js:278 -msgid "extend selected cells above" -msgstr "geselecteerde cellen naar boven uitbreiden" - -#: notebook/static/notebook/js/actions.js:289 -msgid "extend selection below" -msgstr "selectie naar onder uitbreiden" - -#: notebook/static/notebook/js/actions.js:290 -msgid "extend selected cells below" -msgstr "geselecteerde cellen naar onder uitbreiden" - -#: notebook/static/notebook/js/actions.js:301 -#: notebook/static/notebook/js/actions.js:302 -msgid "cut selected cells" -msgstr "geselecteerde cellen knippen" - -#: notebook/static/notebook/js/actions.js:312 -#: notebook/static/notebook/js/actions.js:313 -msgid "copy selected cells" -msgstr "geselecteerde cellen kopiëren" - -#: notebook/static/notebook/js/actions.js:327 -#: notebook/static/notebook/js/actions.js:328 -msgid "paste cells above" -msgstr "cellen erboven plakken" - -#: notebook/static/notebook/js/actions.js:335 -#: notebook/static/notebook/js/actions.js:336 -msgid "paste cells below" -msgstr "cellen eronder plakken" - -#: notebook/static/notebook/js/actions.js:344 -#: notebook/static/notebook/js/actions.js:345 -msgid "insert cell above" -msgstr "cel erboven invoegen" - -#: notebook/static/notebook/js/actions.js:354 -#: notebook/static/notebook/js/actions.js:355 -msgid "insert cell below" -msgstr "cel eronder invoegen" - -#: notebook/static/notebook/js/actions.js:365 -#: notebook/static/notebook/js/actions.js:366 -msgid "change cell to code" -msgstr "cel wijzigen naar code" - -#: notebook/static/notebook/js/actions.js:373 -#: notebook/static/notebook/js/actions.js:374 -msgid "change cell to markdown" -msgstr "cel wijzigen naar markdown" - -#: notebook/static/notebook/js/actions.js:381 -#: notebook/static/notebook/js/actions.js:382 -msgid "change cell to raw" -msgstr "cel wijzigen naar raw" - -#: notebook/static/notebook/js/actions.js:389 -#: notebook/static/notebook/js/actions.js:390 -msgid "change cell to heading 1" -msgstr "cel wijzigen naar header 1" - -#: notebook/static/notebook/js/actions.js:397 -#: notebook/static/notebook/js/actions.js:398 -msgid "change cell to heading 2" -msgstr "cel wijzigen naar header 2" - -#: notebook/static/notebook/js/actions.js:405 -#: notebook/static/notebook/js/actions.js:406 -msgid "change cell to heading 3" -msgstr "cel wijzigen naar header 3" - -#: notebook/static/notebook/js/actions.js:413 -#: notebook/static/notebook/js/actions.js:414 -msgid "change cell to heading 4" -msgstr "cel wijzigen naar header 4" - -#: notebook/static/notebook/js/actions.js:421 -#: notebook/static/notebook/js/actions.js:422 -msgid "change cell to heading 5" -msgstr "cel wijzigen naar header 5" - -#: notebook/static/notebook/js/actions.js:429 -#: notebook/static/notebook/js/actions.js:430 -msgid "change cell to heading 6" -msgstr "cel wijzigen naar header 6" - -#: notebook/static/notebook/js/actions.js:437 -msgid "toggle cell output" -msgstr "celuitvoer in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:438 -msgid "toggle output of selected cells" -msgstr "uitvoer van geselecteerde cellen in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:445 -msgid "toggle cell scrolling" -msgstr "scrollen van cellen in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:446 -msgid "toggle output scrolling of selected cells" -msgstr "scrollen van uitvoer van geselecteerde cellen in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:453 -msgid "clear cell output" -msgstr "verwijder celuitvoer" - -#: notebook/static/notebook/js/actions.js:454 -msgid "clear output of selected cells" -msgstr "verwijder uitvoer van geselecteerde cellen" - -#: notebook/static/notebook/js/actions.js:460 -msgid "move cells down" -msgstr "cellen naar beneden verplaatsen" - -#: notebook/static/notebook/js/actions.js:461 -msgid "move selected cells down" -msgstr "geselecteerde cellen naar beneden verplaatsen" - -#: notebook/static/notebook/js/actions.js:469 -msgid "move cells up" -msgstr "cellen omhoog verplaatsen" - -#: notebook/static/notebook/js/actions.js:470 -msgid "move selected cells up" -msgstr "geselecteerde cellen omhoog verplaatsen" - -#: notebook/static/notebook/js/actions.js:478 -#: notebook/static/notebook/js/actions.js:479 -msgid "toggle line numbers" -msgstr "regelnummers in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:486 -#: notebook/static/notebook/js/actions.js:487 -msgid "show keyboard shortcuts" -msgstr "sneltoetsen weergeven" - -#: notebook/static/notebook/js/actions.js:494 -msgid "delete cells" -msgstr "cellen verwijderen" - -#: notebook/static/notebook/js/actions.js:495 -msgid "delete selected cells" -msgstr "geselecteerde cellen verwijderen" - -#: notebook/static/notebook/js/actions.js:502 -#: notebook/static/notebook/js/actions.js:503 -msgid "undo cell deletion" -msgstr "celverwijdering ongedaan maken" - -#: notebook/static/notebook/js/actions.js:512 -msgid "merge cell with previous cell" -msgstr "cel samenvoegen met vorige cel" - -#: notebook/static/notebook/js/actions.js:513 -msgid "merge cell above" -msgstr "cel erboven samenvoegen" - -#: notebook/static/notebook/js/actions.js:519 -msgid "merge cell with next cell" -msgstr "cel samenvoegen met volgende cel" - -#: notebook/static/notebook/js/actions.js:520 -msgid "merge cell below" -msgstr "cel eronder samenvoegen" - -#: notebook/static/notebook/js/actions.js:527 -#: notebook/static/notebook/js/actions.js:528 -msgid "merge selected cells" -msgstr "geselecteerde cellen samenvoegen" - -#: notebook/static/notebook/js/actions.js:535 -msgid "merge cells" -msgstr "cellen samenvoegen" - -#: notebook/static/notebook/js/actions.js:536 -msgid "" -"merge selected cells, or current cell with cell below if only one cell is " -"selected" -msgstr "" -"geselecteerde cellen of huidige cel samenvoegen met cel eronder als " -"slechts één cel is geselecteerd" - -#: notebook/static/notebook/js/actions.js:549 -msgid "show command pallette" -msgstr "opdrachtpallette weergeven" - -#: notebook/static/notebook/js/actions.js:550 -msgid "open the command palette" -msgstr "opdrachtpallette openen" - -#: notebook/static/notebook/js/actions.js:557 -msgid "toggle all line numbers" -msgstr "alle regelnummers in- en uitschakelen" - -#: notebook/static/notebook/js/actions.js:558 -msgid "toggles line numbers in all cells, and persist the setting" -msgstr "lijnnummers in alle cellen in- of uitschakelen en de instelling aanhouden" - -#: notebook/static/notebook/js/actions.js:569 -msgid "show all line numbers" -msgstr "alle regelnummers weergeven" - -#: notebook/static/notebook/js/actions.js:570 -msgid "show line numbers in all cells, and persist the setting" -msgstr "lijnnummers in alle cellen weergeven en de instelling aanhouden" - -#: notebook/static/notebook/js/actions.js:579 -msgid "hide all line numbers" -msgstr "alle regelnummers verbergen" - -#: notebook/static/notebook/js/actions.js:580 -msgid "hide line numbers in all cells, and persist the setting" -msgstr "regelnummers in alle cellen verbergen en de instelling aanhouden" - -#: notebook/static/notebook/js/actions.js:589 -msgid "toggle header" -msgstr "koptekst in- en uitschakelen" - -#: notebook/static/notebook/js/actions.js:590 -msgid "switch between showing and hiding the header" -msgstr "schakelen tussen het weergeven en verbergen van de koptekst" - -#: notebook/static/notebook/js/actions.js:605 -#: notebook/static/notebook/js/actions.js:606 -msgid "show the header" -msgstr "de koptekst weergeven" - -#: notebook/static/notebook/js/actions.js:615 -#: notebook/static/notebook/js/actions.js:616 -msgid "hide the header" -msgstr "de koptekst verbergen" - -#: notebook/static/notebook/js/actions.js:646 -msgid "toggle toolbar" -msgstr "werkbalk schakelen" - -#: notebook/static/notebook/js/actions.js:647 -msgid "switch between showing and hiding the toolbar" -msgstr "schakelen tussen het weergeven en verbergen van de werkbalk" - -#: notebook/static/notebook/js/actions.js:660 -#: notebook/static/notebook/js/actions.js:661 -msgid "show the toolbar" -msgstr "de werkbalk weergeven" - -#: notebook/static/notebook/js/actions.js:669 -#: notebook/static/notebook/js/actions.js:670 -msgid "hide the toolbar" -msgstr "de werkbalk verbergen" - -#: notebook/static/notebook/js/actions.js:678 -#: notebook/static/notebook/js/actions.js:679 -msgid "close the pager" -msgstr "de pager sluiten" - -#: notebook/static/notebook/js/actions.js:704 -msgid "ignore" -msgstr "Negeren" - -#: notebook/static/notebook/js/actions.js:710 -#: notebook/static/notebook/js/actions.js:711 -msgid "move cursor up" -msgstr "cursor omhoog verplaatsen" - -#: notebook/static/notebook/js/actions.js:731 -#: notebook/static/notebook/js/actions.js:732 -msgid "move cursor down" -msgstr "cursor omlaag verplaatsen" - -#: notebook/static/notebook/js/actions.js:750 -#: notebook/static/notebook/js/actions.js:751 -msgid "scroll notebook down" -msgstr "scroll notebook omlaag" - -#: notebook/static/notebook/js/actions.js:760 -#: notebook/static/notebook/js/actions.js:761 -msgid "scroll notebook up" -msgstr "scroll notebook omhoog" - -#: notebook/static/notebook/js/actions.js:770 -msgid "scroll cell center" -msgstr "scroll cel naar het midden" - -#: notebook/static/notebook/js/actions.js:771 -msgid "Scroll the current cell to the center" -msgstr "De huidige cel naar het midden scrollen" - -#: notebook/static/notebook/js/actions.js:781 -msgid "scroll cell top" -msgstr "scroll cel naar boven" - -#: notebook/static/notebook/js/actions.js:782 -msgid "Scroll the current cell to the top" -msgstr "De huidige cel volledig naar boven scrollen" - -#: notebook/static/notebook/js/actions.js:792 -msgid "duplicate notebook" -msgstr "dupliceer notebook" - -#: notebook/static/notebook/js/actions.js:793 -msgid "Create and open a copy of the current notebook" -msgstr "Een kopie van het huidige notebook maken en openen" - -#: notebook/static/notebook/js/actions.js:799 -msgid "trust notebook" -msgstr "vertrouw notebook" - -#: notebook/static/notebook/js/actions.js:800 -msgid "Trust the current notebook" -msgstr "Het huidige notebook vertrouwen" - -#: notebook/static/notebook/js/actions.js:806 -msgid "rename notebook" -msgstr "naam van notebook wijzigen" - -#: notebook/static/notebook/js/actions.js:807 -msgid "Rename the current notebook" -msgstr "De naam van het huidige notebook wijzigen" - -#: notebook/static/notebook/js/actions.js:813 -msgid "toggle all cells output collapsed" -msgstr "alle samengevouwen celuitvoer in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:814 -msgid "Toggle the hidden state of all output areas" -msgstr "De zichtbaarheid status van alle uitvoergebieden in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:820 -msgid "toggle all cells output scrolled" -msgstr "alle cellenuitvoer in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:821 -msgid "Toggle the scrolling state of all output areas" -msgstr "De scroll-status van alle uitvoergebieden in- of uitschakelen" - -#: notebook/static/notebook/js/actions.js:828 -msgid "clear all cells output" -msgstr "alle cellenuitvoer wissen" - -#: notebook/static/notebook/js/actions.js:829 -msgid "Clear the content of all the outputs" -msgstr "De inhoud van alle celuitvoer wissen" - -#: notebook/static/notebook/js/actions.js:835 -msgid "save notebook" -msgstr "notebook opslaan" - -#: notebook/static/notebook/js/actions.js:836 -msgid "Save and Checkpoint" -msgstr "Opslaan en checkpoint" - -#: notebook/static/notebook/js/cell.js:79 -msgid "Warning: accessing Cell.cm_config directly is deprecated." -msgstr "" -"Waarschuwing: rechtstreeks toegang tot Cell.cm_config wordt afgeschaft." - -#: notebook/static/notebook/js/cell.js:763 -#, python-format -msgid "Unrecognized cell type: %s" -msgstr "Niet-herkende celtype: %s" - -#: notebook/static/notebook/js/cell.js:777 -msgid "Unrecognized cell type" -msgstr "Niet-herkende celtype" - -#: notebook/static/notebook/js/celltoolbar.js:296 -#, python-format -msgid "Error in cell toolbar callback %s" -msgstr "Fout in callback-functie van de celwerkbalk" - -#: notebook/static/notebook/js/clipboard.js:53 -#, python-format -msgid "Clipboard types: %s" -msgstr "Klembordtypen: %s" - -#: notebook/static/notebook/js/clipboard.js:96 -msgid "Dialog for paste from system clipboard" -msgstr "Dialoogvenster voor plakken van het klembord van het systeem" - -#: notebook/static/notebook/js/clipboard.js:109 -msgid "Ctrl-V" -msgstr "Ctrl-V" - -#: notebook/static/notebook/js/clipboard.js:111 -msgid "Cmd-V" -msgstr "Cmd-V" - -#: notebook/static/notebook/js/clipboard.js:113 -#, python-format -msgid "Press %s again to paste" -msgstr "Druk nogmaals op %s om te plakken" - -#: notebook/static/notebook/js/clipboard.js:116 -msgid "Why is this needed? " -msgstr "Waarom is dit nodig? " - -#: notebook/static/notebook/js/clipboard.js:118 -msgid "We can't get paste events in this browser without a text box. " -msgstr "" -"We kunnen niet plakken in deze browser zonder tekstvak. " - -#: notebook/static/notebook/js/clipboard.js:119 -msgid "There's an invisible text box focused in this dialog." -msgstr "Er is een onzichtbaar tekstvak geopend in dit dialoogvenster." - -#: notebook/static/notebook/js/clipboard.js:125 -#, python-format -msgid "%s to paste" -msgstr "%s plakken" - -#: notebook/static/notebook/js/codecell.js:310 -msgid "Can't execute cell since kernel is not set." -msgstr "Kan geen cel uitvoeren omdat kernel niet is ingesteld." - -#: notebook/static/notebook/js/codecell.js:472 -msgid "In" -msgstr "In" - -#: notebook/static/notebook/js/kernelselector.js:269 -#, python-format -msgid "Could not find a kernel matching %s. Please select a kernel:" -msgstr "Kon geen kernel vinden die overeenkomt met %s. Selecteer een kernel:" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Continue Without Kernel" -msgstr "Doorgaan zonder kernel" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Set Kernel" -msgstr "Kernel instellen" - -#: notebook/static/notebook/js/kernelselector.js:281 -msgid "Kernel not found" -msgstr "Kernel niet gevonden" - -#: notebook/static/notebook/js/kernelselector.js:319 -#: notebook/static/tree/js/newnotebook.js:99 -msgid "Creating Notebook Failed" -msgstr "Notebook maken is mislukt" - -#: notebook/static/notebook/js/kernelselector.js:320 -#: notebook/static/tree/js/notebooklist.js:1360 -#, python-format -msgid "The error was: %s" -msgstr "De fout was: %s" - -#: notebook/static/notebook/js/maintoolbar.js:54 -msgid "Run" -msgstr "Uitvoeren" - -#: notebook/static/notebook/js/maintoolbar.js:76 -msgid "Code" -msgstr "Code" - -#: notebook/static/notebook/js/maintoolbar.js:77 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/static/notebook/js/maintoolbar.js:78 -msgid "Raw NBConvert" -msgstr "Raw NBConvert" - -#: notebook/static/notebook/js/maintoolbar.js:79 -msgid "Heading" -msgstr "Headers" - -#: notebook/static/notebook/js/maintoolbar.js:115 -msgid "unrecognized cell type:" -msgstr "niet-herkende celtype:" - -#: notebook/static/notebook/js/mathjaxutils.js:45 -#, python-format -msgid "Failed to retrieve MathJax from '%s'" -msgstr "Kan MathJax niet ophalen uit '%s'" - -#: notebook/static/notebook/js/mathjaxutils.js:47 -msgid "Math/LaTeX rendering will be disabled." -msgstr "Wiskunde/LaTeX-rendering wordt uitgeschakeld." - -#: notebook/static/notebook/js/menubar.js:220 -msgid "Trusted Notebook" -msgstr "Vertrouwd notebook" - -#: notebook/static/notebook/js/menubar.js:226 -msgid "Trust Notebook" -msgstr "Notebook vertrouwen" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16 -#: notebook/static/notebook/js/menubar.js:383 -msgid "None" -msgstr "Geen" - -#: notebook/static/notebook/js/menubar.js:406 -msgid "No checkpoints" -msgstr "Geen checkpoints" - -#: notebook/static/notebook/js/menubar.js:465 -msgid "Opens in a new window" -msgstr "Opent in een nieuw venster" - -#: notebook/static/notebook/js/notebook.js:431 -msgid "Autosave in progress, latest changes may be lost." -msgstr "" -"Bezig met automatisch opslaan, de laatste wijzigingen kunnen verloren " -"gaan." - -#: notebook/static/notebook/js/notebook.js:433 -msgid "Unsaved changes will be lost." -msgstr "Niet-opgeslagen wijzigingen gaan verloren." - -#: notebook/static/notebook/js/notebook.js:438 -msgid "The Kernel is busy, outputs may be lost." -msgstr "De Kernel is bezet, uitvoeren kunnen verloren gaan." - -#: notebook/static/notebook/js/notebook.js:461 -msgid "This notebook is version %1$s, but we only fully support up to %2$s." -msgstr "" -"Deze notebook is versie %1$s, maar we ondersteunen alleen volledig tot %2$s." - -#: notebook/static/notebook/js/notebook.js:463 -msgid "" -"You can still work with this notebook, but cell and output types introduced " -"in later notebook versions will not be available." -msgstr "" -"U kunt nog steeds met deze notebook werken, maar cel- en uitvoertypen die in " -"latere notebookversies zijn geïntroduceerd, zijn niet beschikbaar." - -#: notebook/static/notebook/js/notebook.js:470 -msgid "Restart and Run All Cells" -msgstr "Herstarten en alle cellen uitvoeren" - -#: notebook/static/notebook/js/notebook.js:471 -msgid "Restart and Clear All Outputs" -msgstr "Herstarten en alle uitvoer wissen" - -#: notebook/static/notebook/js/notebook.js:472 -msgid "Restart" -msgstr "Herstarten" - -#: notebook/static/notebook/js/notebook.js:473 -msgid "Continue Running" -msgstr "Doorgaan met uitvoeren" - -#: notebook/static/notebook/js/notebook.js:474 -msgid "Reload" -msgstr "Reload" - -#: notebook/static/notebook/js/notebook.js:476 -msgid "Overwrite" -msgstr "Overschrijven" - -#: notebook/static/notebook/js/notebook.js:477 -msgid "Trust" -msgstr "Vertrouwen" - -#: notebook/static/notebook/js/notebook.js:478 -msgid "Revert" -msgstr "Terugkeren" - -#: notebook/static/notebook/js/notebook.js:483 -msgid "Newer Notebook" -msgstr "Nieuwer notebook" - -#: notebook/static/notebook/js/notebook.js:1548 -msgid "Use markdown headings" -msgstr "Markdown headers gebruiken" - -#: notebook/static/notebook/js/notebook.js:1550 -msgid "" -"Jupyter no longer uses special heading cells. Instead, write your headings " -"in Markdown cells using # characters:" -msgstr "" -"Jupyter maakt geen gebruik meer van speciale headercellen. Schrijf in plaats " -"daarvan uw headers in Markdown-cellen met # tekens:" - -#: notebook/static/notebook/js/notebook.js:1553 -msgid "## This is a level 2 heading" -msgstr "## Dit is een niveau 2 header" - -#: notebook/static/notebook/js/notebook.js:2248 -msgid "Restart kernel and re-run the whole notebook?" -msgstr "Kernel herstarten en het hele notebook opnieuw uitvoeren?" - -#: notebook/static/notebook/js/notebook.js:2250 -msgid "" -"Are you sure you want to restart the current kernel and re-execute the whole" -" notebook? All variables and outputs will be lost." -msgstr "" -"Weet u zeker dat u de huidige kernel wilt herstarten en het hele " -"notebook opnieuw wilt uitvoeren? Alle variabelen en uitgangen gaan " -"verloren." - -#: notebook/static/notebook/js/notebook.js:2275 -msgid "Restart kernel and clear all output?" -msgstr "Herstart kernel en verwijder alle output?" - -#: notebook/static/notebook/js/notebook.js:2277 -msgid "" -"Do you want to restart the current kernel and clear all output? All " -"variables and outputs will be lost." -msgstr "" -"Wilt u de huidige kernel herstarten en alle uitvoer wissen? Alle " -"variabelen en uitgangen gaan verloren." - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Restart kernel?" -msgstr "Kernel herstarten?" - -#: notebook/static/notebook/js/notebook.js:2324 -msgid "" -"Do you want to restart the current kernel? All variables will be lost." -msgstr "" -"Wilt u de huidige kernel herstarten? Alle variabelen gaan verloren." - -#: notebook/static/notebook/js/notebook.js:2320 -msgid "Shutdown kernel?" -msgstr "Kernel afsluiten?" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "" -"Do you want to shutdown the current kernel? All variables will be lost." -msgstr "Wilt u de huidige kernel afsluiten? Alle variabelen gaan verloren." - -#: notebook/static/notebook/js/notebook.js:2734 -msgid "Notebook changed" -msgstr "Notebook gewijzigd" - -#: notebook/static/notebook/js/notebook.js:2735 -msgid "" -"The notebook file has changed on disk since the last time we opened or saved" -" it. Do you want to overwrite the file on disk with the version open here, " -"or load the version on disk (reload the page) ?" -msgstr "" -"Het notebookbestand op de schijf is gewijzigd sinds de laatste keer dat het " -"geopend of opgeslagen is. Wilt u het bestand op schijf overschrijven" -" met de versie die hier wordt geopend, of de versie op schijf laden (de " -"pagina opnieuw laden) ?" - -#: notebook/static/notebook/js/notebook.js:2782 -#: notebook/static/notebook/js/notebook.js:2990 -msgid "Notebook validation failed" -msgstr "Notebook validatie is mislukt" - -#: notebook/static/notebook/js/notebook.js:2785 -msgid "" -"The save operation succeeded, but the notebook does not appear to be valid. " -"The validation error was:" -msgstr "" -"De opslagbewerking is geslaagd, maar het notebook lijkt niet geldig te " -"zijn. De validatiefout was:" - -#: notebook/static/notebook/js/notebook.js:2836 -msgid "" -"A trusted Jupyter notebook may execute hidden malicious code when you open " -"it. Selecting trust will immediately reload this notebook in a trusted " -"state. For more information, see the Jupyter security documentation: " -msgstr "" -"Een vertrouwd Jupyter-notebook kan verborgen schadelijke code uitvoeren " -"wanneer u het opent. Als u vertrouwensstatus selecteert, wordt dit " -"notebook onmiddellijk opnieuw geladen in een vertrouwde status. Zie voor " -"meer informatie de beveiligingsdocumentatie van Jupyter: " - -#: notebook/static/notebook/js/notebook.js:2840 -msgid "here" -msgstr "hier" - -#: notebook/static/notebook/js/notebook.js:2848 -msgid "Trust this notebook?" -msgstr "Vertrouw je dit notebook?" - -#: notebook/static/notebook/js/notebook.js:2981 -msgid "Notebook failed to load" -msgstr "Notebook kan niet worden geladen" - -#: notebook/static/notebook/js/notebook.js:2983 -msgid "The error was: " -msgstr "De fout was: " - -#: notebook/static/notebook/js/notebook.js:2987 -msgid "See the error console for details." -msgstr "Zie de foutconsole voor meer informatie." - -#: notebook/static/notebook/js/notebook.js:2995 -msgid "The notebook also failed validation:" -msgstr "De notebook validatie is ook mislukt:" - -#: notebook/static/notebook/js/notebook.js:2997 -msgid "" -"An invalid notebook may not function properly. The validation error was:" -msgstr "" -"Een ongeldig notebook werkt mogelijk niet goed. De validatiefout was:" - -#: notebook/static/notebook/js/notebook.js:3036 -#, python-format -msgid "" -"This notebook has been converted from an older notebook format to the " -"current notebook format v(%s)." -msgstr "" -"Deze notebook is geconverteerd van een oudere notebookindeling naar de " -"huidige notebookindeling v(%s)." - -#: notebook/static/notebook/js/notebook.js:3038 -#, python-format -msgid "" -"This notebook has been converted from a newer notebook format to the current" -" notebook format v(%s)." -msgstr "" -"Deze notebook is geconverteerd van een nieuwere notebookindeling naar de " -"huidige notebookindeling v(%s)." - -#: notebook/static/notebook/js/notebook.js:3046 -msgid "" -"The next time you save this notebook, the current notebook format will be " -"used." -msgstr "" -"De volgende keer dat u dit notebook opslaat, wordt de huidige " -"notebookindeling gebruikt." - -#: notebook/static/notebook/js/notebook.js:3051 -msgid "Older versions of Jupyter may not be able to read the new format." -msgstr "" -"Oudere versies van Jupyter kunnen het nieuwe formaat mogelijk niet lezen." - -#: notebook/static/notebook/js/notebook.js:3053 -msgid "Some features of the original notebook may not be available." -msgstr "" -"Sommige functies van de originele notebook zijn mogelijk niet beschikbaar." - -#: notebook/static/notebook/js/notebook.js:3056 -msgid "" -"To preserve the original version, close the notebook without saving it." -msgstr "" -"Als u de oorspronkelijke versie wilt behouden, sluit u het notebook " -"zonder deze op te slaan." - -#: notebook/static/notebook/js/notebook.js:3061 -msgid "Notebook converted" -msgstr "Notebook geconverteerd" - -#: notebook/static/notebook/js/notebook.js:3083 -msgid "(No name)" -msgstr "(Geen naam)" - -#: notebook/static/notebook/js/notebook.js:3131 -#, python-format -msgid "" -"An unknown error occurred while loading this notebook. This version can load" -" notebook formats %s or earlier. See the server log for details." -msgstr "" -"Er is een onbekende fout opgetreden tijdens het laden van dit notebook. " -"Deze versie kan notebook-indelingen %s of eerder laden. Zie het " -"serverlogboek voor meer informatie." - -#: notebook/static/notebook/js/notebook.js:3142 -msgid "Error loading notebook" -msgstr "Fout bij het laden van notebook" - -#: notebook/static/notebook/js/notebook.js:3243 -msgid "Are you sure you want to revert the notebook to the latest checkpoint?" -msgstr "" -"Weet je zeker dat je het notebook wilt terugdraaien naar het laatste " -"checkpoint?" - -#: notebook/static/notebook/js/notebook.js:3246 -msgid "This cannot be undone." -msgstr "Dit kan niet ongedaan worden gemaakt." - -#: notebook/static/notebook/js/notebook.js:3249 -msgid "The checkpoint was last updated at:" -msgstr "Het checkpoint is voor het laatst bijgewerkt op:" - -#: notebook/static/notebook/js/notebook.js:3260 -msgid "Revert notebook to checkpoint" -msgstr "Notebook terugzetten naar checkpoint" - -#: notebook/static/notebook/js/notificationarea.js:77 -#: notebook/static/notebook/js/tour.js:61 -#: notebook/static/notebook/js/tour.js:67 -msgid "Edit Mode" -msgstr "Bewerkingsmodus" - -#: notebook/static/notebook/js/notificationarea.js:84 -#: notebook/static/notebook/js/notificationarea.js:88 -#: notebook/static/notebook/js/tour.js:54 -msgid "Command Mode" -msgstr "Opdrachtmodus" - -#: notebook/static/notebook/js/notificationarea.js:95 -msgid "Kernel Created" -msgstr "Kernel aangemaakt" - -#: notebook/static/notebook/js/notificationarea.js:99 -msgid "Connecting to kernel" -msgstr "Verbinding maken met kernel" - -#: notebook/static/notebook/js/notificationarea.js:103 -msgid "Not Connected" -msgstr "Niet verbonden" - -#: notebook/static/notebook/js/notificationarea.js:106 -msgid "click to reconnect" -msgstr "klik om opnieuw verbinding te maken" - -#: notebook/static/notebook/js/notificationarea.js:115 -msgid "Restarting kernel" -msgstr "Kernel herstarten" - -#: notebook/static/notebook/js/notificationarea.js:129 -msgid "Kernel Restarting" -msgstr "Kernel herstarten" - -#: notebook/static/notebook/js/notificationarea.js:130 -msgid "The kernel appears to have died. It will restart automatically." -msgstr "" -"De kernel lijkt te zijn gestopt. Hij wordt automatisch herstart." - -#: notebook/static/notebook/js/notificationarea.js:140 -#: notebook/static/notebook/js/notificationarea.js:198 -#: notebook/static/notebook/js/notificationarea.js:218 -msgid "Dead kernel" -msgstr "Gestopte kernel" - -#: notebook/static/notebook/js/notificationarea.js:141 -#: notebook/static/notebook/js/notificationarea.js:219 -#: notebook/static/notebook/js/notificationarea.js:266 -msgid "Kernel Dead" -msgstr "Kernel is gestopt" - -#: notebook/static/notebook/js/notificationarea.js:145 -msgid "Interrupting kernel" -msgstr "Kernel onderbreken" - -#: notebook/static/notebook/js/notificationarea.js:151 -msgid "No Connection to Kernel" -msgstr "Geen verbinding met kernel" - -#: notebook/static/notebook/js/notificationarea.js:161 -msgid "" -"A connection to the notebook server could not be established. The notebook " -"will continue trying to reconnect. Check your network connection or notebook" -" server configuration." -msgstr "" -"Er kan geen verbinding met de notebookserver worden gemaakt. Het notebook" -" blijft proberen opnieuw verbinding te maken. Controleer de configuratie van" -" uw netwerkverbinding of laptopserver." - -#: notebook/static/notebook/js/notificationarea.js:166 -msgid "Connection failed" -msgstr "Verbinding is mislukt" - -#: notebook/static/notebook/js/notificationarea.js:179 -msgid "No kernel" -msgstr "Geen kernel" - -#: notebook/static/notebook/js/notificationarea.js:180 -msgid "Kernel is not running" -msgstr "Kernel is niet actief" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Don't Restart" -msgstr "Niet herstarten" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Try Restarting Now" -msgstr "Probeer nu te herstarten" - -#: notebook/static/notebook/js/notificationarea.js:191 -msgid "" -"The kernel has died, and the automatic restart has failed. It is possible " -"the kernel cannot be restarted. If you are not able to restart the kernel, " -"you will still be able to save the notebook, but running code will no longer" -" work until the notebook is reopened." -msgstr "" -"De kernel is gestopt en de automatische herstart is mislukt. Het is " -"mogelijk dat de kernel niet kan worden herstart. Als u de kernel niet" -" start, kan u het notebook nog steeds opslaan, maar werkt de code " -"niet meer totdat het notebook opnieuw is geopend." - -#: notebook/static/notebook/js/notificationarea.js:225 -msgid "No Kernel" -msgstr "Geen kernel" - -#: notebook/static/notebook/js/notificationarea.js:252 -msgid "Failed to start the kernel" -msgstr "Kan de kernel niet starten" - -#: notebook/static/notebook/js/notificationarea.js:272 -#: notebook/static/notebook/js/notificationarea.js:292 -#: notebook/static/notebook/js/notificationarea.js:306 -msgid "Kernel Busy" -msgstr "Kernel bezet" - -#: notebook/static/notebook/js/notificationarea.js:273 -msgid "Kernel starting, please wait..." -msgstr "Kernel beginnen, wachten..." - -#: notebook/static/notebook/js/notificationarea.js:279 -#: notebook/static/notebook/js/notificationarea.js:286 -msgid "Kernel Idle" -msgstr "Kernel Idle" - -#: notebook/static/notebook/js/notificationarea.js:280 -msgid "Kernel ready" -msgstr "Kernel klaar" - -#: notebook/static/notebook/js/notificationarea.js:297 -msgid "Using kernel: " -msgstr "Kernel gebruiken: " - -#: notebook/static/notebook/js/notificationarea.js:298 -msgid "Only candidate for language: %1$s was %2$s." -msgstr "Enige kandidaat voor taal: %1$s was %2$s." - -#: notebook/static/notebook/js/notificationarea.js:319 -msgid "Loading notebook" -msgstr "Notebook laden" - -#: notebook/static/notebook/js/notificationarea.js:322 -msgid "Notebook loaded" -msgstr "Notebook geladen" - -#: notebook/static/notebook/js/notificationarea.js:325 -msgid "Saving notebook" -msgstr "Notebook opslaan" - -#: notebook/static/notebook/js/notificationarea.js:328 -msgid "Notebook saved" -msgstr "Notebook opgeslagen" - -#: notebook/static/notebook/js/notificationarea.js:331 -msgid "Notebook save failed" -msgstr "Notebook opslaan is mislukt" - -#: notebook/static/notebook/js/notificationarea.js:334 -msgid "Notebook copy failed" -msgstr "Notebook kopiëren is mislukt" - -#: notebook/static/notebook/js/notificationarea.js:339 -msgid "Checkpoint created" -msgstr "Checkpoint gemaakt" - -#: notebook/static/notebook/js/notificationarea.js:347 -msgid "Checkpoint failed" -msgstr "Checkpoint is mislukt" - -#: notebook/static/notebook/js/notificationarea.js:350 -msgid "Checkpoint deleted" -msgstr "Checkpoint verwijderd" - -#: notebook/static/notebook/js/notificationarea.js:353 -msgid "Checkpoint delete failed" -msgstr "Checkpoint verwijderen is mislukt" - -#: notebook/static/notebook/js/notificationarea.js:356 -msgid "Restoring to checkpoint..." -msgstr "Herstellen naar checkpoint..." - -#: notebook/static/notebook/js/notificationarea.js:359 -msgid "Checkpoint restore failed" -msgstr "Checkpoint herstel is mislukt" - -#: notebook/static/notebook/js/notificationarea.js:364 -msgid "Autosave disabled" -msgstr "Automatisch opslaan uitgeschakeld" - -#: notebook/static/notebook/js/notificationarea.js:367 -#, python-format -msgid "Saving every %d sec." -msgstr "Het notebook wordt elke %d sec opgeslagen." - -#: notebook/static/notebook/js/notificationarea.js:383 -msgid "Trusted" -msgstr "Vertrouwd" - -#: notebook/static/notebook/js/notificationarea.js:385 -msgid "Not Trusted" -msgstr "Niet vertrouwd" - -#: notebook/static/notebook/js/outputarea.js:75 -msgid "click to expand output" -msgstr "klik om de uitvoer volledig weer te geven" - -#: notebook/static/notebook/js/outputarea.js:79 -msgid "click to expand output; double click to hide output" -msgstr "" -"klik om de uitvoer te laten verschijnen; dubbelklikken om uitvoer te verbergen" - -#: notebook/static/notebook/js/outputarea.js:167 -msgid "click to unscroll output; double click to hide" -msgstr "klik om de uitvoer te ontscrollen; dubbelklikken om te verbergen" - -#: notebook/static/notebook/js/outputarea.js:174 -msgid "click to scroll output; double click to hide" -msgstr "klik om de uitvoer te scrollen; dubbelklikken om te verbergen" - -#: notebook/static/notebook/js/outputarea.js:422 -msgid "Javascript error adding output!" -msgstr "Javascript fout bij het toevoegen van uitvoer!" - -#: notebook/static/notebook/js/outputarea.js:427 -msgid "See your browser Javascript console for more details." -msgstr "Zie uw browser Javascript console voor meer details." - -#: notebook/static/notebook/js/outputarea.js:468 -#, python-format -msgid "Out[%d]:" -msgstr "Out[%d]:" - -#: notebook/static/notebook/js/outputarea.js:577 -#, python-format -msgid "Unrecognized output: %s" -msgstr "Niet-herkende uitvoer: %s" - -#: notebook/static/notebook/js/pager.js:36 -msgid "Open the pager in an external window" -msgstr "De pager openen in een extern venster" - -#: notebook/static/notebook/js/pager.js:45 -msgid "Close the pager" -msgstr "De pager sluiten" - -#: notebook/static/notebook/js/pager.js:148 -msgid "Jupyter Pager" -msgstr "Jupyter Pager" - -#: notebook/static/notebook/js/quickhelp.js:39 -#: notebook/static/notebook/js/quickhelp.js:49 -#: notebook/static/notebook/js/quickhelp.js:50 -msgid "go to cell start" -msgstr "ga naar celstart" - -#: notebook/static/notebook/js/quickhelp.js:40 -#: notebook/static/notebook/js/quickhelp.js:51 -#: notebook/static/notebook/js/quickhelp.js:52 -msgid "go to cell end" -msgstr "ga naar het celeinde" - -#: notebook/static/notebook/js/quickhelp.js:41 -#: notebook/static/notebook/js/quickhelp.js:53 -msgid "go one word left" -msgstr "één woord naar links gaan" - -#: notebook/static/notebook/js/quickhelp.js:42 -#: notebook/static/notebook/js/quickhelp.js:54 -msgid "go one word right" -msgstr "ga een woord naar rechts" - -#: notebook/static/notebook/js/quickhelp.js:43 -#: notebook/static/notebook/js/quickhelp.js:55 -msgid "delete word before" -msgstr "woord ervoor verwijderen" - -#: notebook/static/notebook/js/quickhelp.js:44 -#: notebook/static/notebook/js/quickhelp.js:56 -msgid "delete word after" -msgstr "woord erna verwijderen" - -#: notebook/static/notebook/js/quickhelp.js:61 -msgid "code completion or indent" -msgstr "code aanvulling of inspringing" - -#: notebook/static/notebook/js/quickhelp.js:62 -msgid "tooltip" -msgstr "Tooltip" - -#: notebook/static/notebook/js/quickhelp.js:63 -msgid "indent" -msgstr "inspringing" - -#: notebook/static/notebook/js/quickhelp.js:64 -msgid "dedent" -msgstr "inspringing ongedaan maken" - -#: notebook/static/notebook/js/quickhelp.js:65 -msgid "select all" -msgstr "selecteer alle" - -#: notebook/static/notebook/js/quickhelp.js:66 -msgid "undo" -msgstr "Ongedaan maken" - -#: notebook/static/notebook/js/quickhelp.js:67 -#: notebook/static/notebook/js/quickhelp.js:68 -msgid "redo" -msgstr "Opnieuw" - -#: notebook/static/notebook/js/quickhelp.js:102 -#: notebook/static/notebook/js/quickhelp.js:243 -msgid "Shift" -msgstr "Shift" - -#: notebook/static/notebook/js/quickhelp.js:103 -msgid "Alt" -msgstr "Alt" - -#: notebook/static/notebook/js/quickhelp.js:104 -msgid "Up" -msgstr "Omhoog" - -#: notebook/static/notebook/js/quickhelp.js:105 -msgid "Down" -msgstr "Omlaag" - -#: notebook/static/notebook/js/quickhelp.js:106 -msgid "Left" -msgstr "Links" - -#: notebook/static/notebook/js/quickhelp.js:107 -msgid "Right" -msgstr "Recht" - -#: notebook/static/notebook/js/quickhelp.js:108 -#: notebook/static/notebook/js/quickhelp.js:246 -msgid "Tab" -msgstr "Tab" - -#: notebook/static/notebook/js/quickhelp.js:109 -msgid "Caps Lock" -msgstr "CAPS-LOCK" - -#: notebook/static/notebook/js/quickhelp.js:110 -#: notebook/static/notebook/js/quickhelp.js:269 -msgid "Esc" -msgstr "Esc" - -#: notebook/static/notebook/js/quickhelp.js:111 -msgid "Ctrl" -msgstr "Ctrl" - -#: notebook/static/notebook/js/quickhelp.js:112 -#: notebook/static/notebook/js/quickhelp.js:290 -msgid "Enter" -msgstr "Enter" - -#: notebook/static/notebook/js/quickhelp.js:113 -msgid "Page Up" -msgstr "Pagina omhoog" - -#: notebook/static/notebook/js/quickhelp.js:114 -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "Page Down" -msgstr "Pagina omlaag" - -#: notebook/static/notebook/js/quickhelp.js:115 -msgid "Home" -msgstr "Home" - -#: notebook/static/notebook/js/quickhelp.js:116 -msgid "End" -msgstr "Einde" - -#: notebook/static/notebook/js/quickhelp.js:117 -#: notebook/static/notebook/js/quickhelp.js:245 -msgid "Space" -msgstr "Spatie" - -#: notebook/static/notebook/js/quickhelp.js:118 -msgid "Backspace" -msgstr "Backspace" - -#: notebook/static/notebook/js/quickhelp.js:119 -msgid "Minus" -msgstr "Minus" - -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "PageUp" -msgstr "PageUp" - -#: notebook/static/notebook/js/quickhelp.js:197 -msgid "The Jupyter Notebook has two different keyboard input modes." -msgstr "De Jupyter Notebook heeft twee verschillende toetsenbordinvoermodi." - -#: notebook/static/notebook/js/quickhelp.js:199 -msgid "" -"Edit mode allows you to type code or text into a cell and is " -"indicated by a green cell border." -msgstr "" -"Edit-modus u code of tekst typen in een cel en wordt aangegeven door " -"een groene celrand." - -#: notebook/static/notebook/js/quickhelp.js:201 -msgid "" -"Command mode binds the keyboard to notebook level commands and is " -"indicated by a grey cell border with a blue left margin." -msgstr "" -"Command-modus het toetsenbord bindt aan opdrachten op notebookniveau " -"en wordt aangegeven door een grijze celrand met een blauwe linkermarge." - -#: notebook/static/notebook/js/quickhelp.js:222 -#: notebook/static/notebook/js/tooltip.js:58 -#: notebook/static/notebook/js/tooltip.js:69 -msgid "Close" -msgstr "Sluiten" - -#: notebook/static/notebook/js/quickhelp.js:225 -msgid "Keyboard shortcuts" -msgstr "Sneltoetsen" - -#: notebook/static/notebook/js/quickhelp.js:240 -msgid "Command" -msgstr "Opdracht" - -#: notebook/static/notebook/js/quickhelp.js:241 -msgid "Control" -msgstr "Controle" - -#: notebook/static/notebook/js/quickhelp.js:242 -msgid "Option" -msgstr "Optie" - -#: notebook/static/notebook/js/quickhelp.js:244 -msgid "Return" -msgstr "Terug" - -#: notebook/static/notebook/js/quickhelp.js:270 -#, python-format -msgid "Command Mode (press %s to enable)" -msgstr "Opdrachtmodus (druk op %s om in te schakelen)" - -#: notebook/static/notebook/js/quickhelp.js:272 -msgid "Edit Shortcuts" -msgstr "Sneltoetsen bewerken" - -#: notebook/static/notebook/js/quickhelp.js:275 -msgid "edit command-mode keyboard shortcuts" -msgstr "Sneltoetsen in de opdrachtmodus bewerken" - -#: notebook/static/notebook/js/quickhelp.js:292 -#, python-format -msgid "Edit Mode (press %s to enable)" -msgstr "Bewerkingsmodus (druk op %s om in te schakelen)" - -#: notebook/static/notebook/js/savewidget.js:49 -msgid "Autosave Failed!" -msgstr "Automatisch opslaan is mislukt!" - -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:846 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Rename" -msgstr "Hernoemen" - -#: notebook/static/notebook/js/savewidget.js:78 -#: notebook/static/tree/js/notebooklist.js:837 -msgid "Enter a new notebook name:" -msgstr "Voer een nieuwe notebooknaam in:" - -#: notebook/static/notebook/js/savewidget.js:86 -msgid "Rename Notebook" -msgstr "De naam van notebook wijzigen" - -#: notebook/static/notebook/js/savewidget.js:98 -msgid "" -"Invalid notebook name. Notebook names must have 1 or more characters and can" -" contain any characters except :/\\. Please enter a new notebook name:" -msgstr "" -"Ongeldige notebooknaam. Notebook-namen moeten 1 of meer tekens bevatten" -" en kunnen tekens bevatten, behalve :/\\. Voer een nieuwe notebooknaam " -"in:" - -#: notebook/static/notebook/js/savewidget.js:103 -msgid "Renaming..." -msgstr "Hernoemen..." - -#: notebook/static/notebook/js/savewidget.js:109 -msgid "Unknown error" -msgstr "Onbekende fout" - -#: notebook/static/notebook/js/savewidget.js:178 -msgid "no checkpoint" -msgstr "geen checkpoint" - -#: notebook/static/notebook/js/savewidget.js:193 -#, python-format -msgid "Last Checkpoint: %s" -msgstr "Laatste checkpoint: %s" - -#: notebook/static/notebook/js/savewidget.js:217 -msgid "(unsaved changes)" -msgstr "(niet-opgeslagen wijzigingen)" - -#: notebook/static/notebook/js/savewidget.js:219 -msgid "(autosaved)" -msgstr "(automatisch opgeslagen)" - -#: notebook/static/notebook/js/searchandreplace.js:74 -#, python-format -msgid "" -"Warning: too many matches (%d). Some changes might not be shown or applied." -msgstr "" -"Waarschuwing: te veel matches (%d). Sommige wijzigingen worden mogelijk " -"niet weergegeven of toegepast." - -#: notebook/static/notebook/js/searchandreplace.js:77 -#, python-format -msgid "%d match" -msgid_plural "%d matches" -msgstr[0] "%d match" -msgstr[1] "%d matches" - -#: notebook/static/notebook/js/searchandreplace.js:145 -msgid "More than 100 matches, aborting" -msgstr "Meer dan 100 matches, afbreken" - -#: notebook/static/notebook/js/searchandreplace.js:166 -msgid "Use regex (JavaScript regex syntax)" -msgstr "Regex gebruiken (JavaScript regex syntax)" - -#: notebook/static/notebook/js/searchandreplace.js:174 -msgid "Replace in selected cells" -msgstr "Vervangen in geselecteerde cellen" - -#: notebook/static/notebook/js/searchandreplace.js:181 -msgid "Match case" -msgstr "Hoofdletters matchen" - -#: notebook/static/notebook/js/searchandreplace.js:187 -msgid "Find" -msgstr "Zoek" - -#: notebook/static/notebook/js/searchandreplace.js:203 -msgid "Replace" -msgstr "Vervangen" - -#: notebook/static/notebook/js/searchandreplace.js:255 -msgid "No matches, invalid or empty regular expression" -msgstr "Geen overeenkomsten, ongeldige of lege reguliere expressie" - -#: notebook/static/notebook/js/searchandreplace.js:370 -msgid "Replace All" -msgstr "Alles vervangen" - -#: notebook/static/notebook/js/searchandreplace.js:374 -msgid "Find and Replace" -msgstr "Zoeken en vervangen" - -#: notebook/static/notebook/js/searchandreplace.js:400 -#: notebook/static/notebook/js/searchandreplace.js:401 -msgid "find and replace" -msgstr "zoeken en vervangen" - -#: notebook/static/notebook/js/textcell.js:551 -msgid "" -"Write raw LaTeX or other formats here, for use with nbconvert. It will not " -"be rendered in the notebook. When passing through nbconvert, a Raw Cell's " -"content is added to the output unmodified." -msgstr "" -"Schrijf hier in LaTeX of ander format, voor gebruik met nbconvert. Het " -"wordt niet weergegeven in het notebook. Bij het doorlopen van nbconvert " -"wordt de inhoud van een Raw Cell ongewijzigd aan de uitvoer toegevoegd." - -#: notebook/static/notebook/js/tooltip.js:41 -msgid "Grow the tooltip vertically (press shift-tab twice)" -msgstr "De tooltip verticaal laten groeien (druk twee keer op shift-tab)" - -#: notebook/static/notebook/js/tooltip.js:48 -msgid "show the current docstring in pager (press shift-tab 4 times)" -msgstr "de huidige docstring weergeven in pager (druk 4 keer op shift-tab)" - -#: notebook/static/notebook/js/tooltip.js:49 -msgid "Open in Pager" -msgstr "Openen in Pager" - -#: notebook/static/notebook/js/tooltip.js:68 -msgid "Tooltip will linger for 10 seconds while you type" -msgstr "De tooltip blijft 10 seconden hangen terwijl u typt" - -#: notebook/static/notebook/js/tour.js:27 -msgid "Welcome to the Notebook Tour" -msgstr "Welkom bij de Notebook Rondleiding" - -#: notebook/static/notebook/js/tour.js:30 -msgid "" -"You can use the left and right arrow keys to go backwards and forwards." -msgstr "U kan de pijltjestoetsen links en rechts gebruiken om heen en weer te gaan." - -#: notebook/static/notebook/js/tour.js:33 -msgid "Filename" -msgstr "Bestandsnaam" - -#: notebook/static/notebook/js/tour.js:35 -msgid "Click here to change the filename for this notebook." -msgstr "Klik hier om de bestandsnaam voor dit notebook te wijzigen." - -#: notebook/static/notebook/js/tour.js:39 -msgid "Notebook Menubar" -msgstr "Menubalk notebook" - -#: notebook/static/notebook/js/tour.js:40 -msgid "" -"The menubar has menus for actions on the notebook, its cells, and the kernel" -" it communicates with." -msgstr "" -"De menubalk heeft menu's voor acties op het notebook, de cellen en de " -"kernel waarmee het communiceert." - -#: notebook/static/notebook/js/tour.js:44 -msgid "Notebook Toolbar" -msgstr "Werkbalk Notebook" - -#: notebook/static/notebook/js/tour.js:45 -msgid "" -"The toolbar has buttons for the most common actions. Hover your mouse over " -"each button for more information." -msgstr "" -"De werkbalk heeft knoppen voor de meest voorkomende acties. Beweeg met je " -"muis over elke knop voor meer informatie." - -#: notebook/static/notebook/js/tour.js:48 -msgid "Mode Indicator" -msgstr "Modus-indicator" - -#: notebook/static/notebook/js/tour.js:50 -msgid "" -"The Notebook has two modes: Edit Mode and Command Mode. In this area, an " -"indicator can appear to tell you which mode you are in." -msgstr "" -"De notebook heeft twee modi: De modus bewerken en de opdrachtmodus. In dit " -"gebied kan een indicator verschijnen om u te vertellen in welke modus u zich" -" bevindt." - -#: notebook/static/notebook/js/tour.js:58 -msgid "" -"Right now you are in Command Mode, and many keyboard shortcuts are " -"available. In this mode, no icon is displayed in the indicator area." -msgstr "" -"Op dit moment bent u in de opdrachtmodus en zijn er veel sneltoetsen " -"beschikbaar. In deze modus wordt geen pictogram weergegeven in het " -"indicatorgebied." - -#: notebook/static/notebook/js/tour.js:64 -msgid "" -"Pressing Enter or clicking in the input text area of the cell " -"switches to Edit Mode." -msgstr "" -"Als u op Enter drukt of klikt in het invoertekstgebied van de cel, " -"schakelt u over naar de bewerkingsmodus." - -#: notebook/static/notebook/js/tour.js:70 -msgid "" -"Notice that the border around the currently active cell changed color. " -"Typing will insert text into the currently active cell." -msgstr "" -"De rand rond de actieve cel is van kleur veranderd. Als u typt, wordt tekst " -"ingevoegd in de actieve cel." - -#: notebook/static/notebook/js/tour.js:73 -msgid "Back to Command Mode" -msgstr "Terug naar de opdrachtmodus" - -#: notebook/static/notebook/js/tour.js:76 -msgid "" -"Pressing Esc or clicking outside of the input text area takes " -"you back to Command Mode." -msgstr "" -"Als u op Esc drukt of buiten het invoertekstgebied klikt, gaat " -"u terug naar de opdrachtmodus." - -#: notebook/static/notebook/js/tour.js:79 -msgid "Keyboard Shortcuts" -msgstr "Sneltoetsen" - -#: notebook/static/notebook/js/tour.js:91 -msgid "You can click here to get a list of all of the keyboard shortcuts." -msgstr "U hier klikken om een lijst van alle sneltoetsen te krijgen." - -#: notebook/static/notebook/js/tour.js:94 -#: notebook/static/notebook/js/tour.js:100 -msgid "Kernel Indicator" -msgstr "Kernel Indicator" - -#: notebook/static/notebook/js/tour.js:97 -msgid "" -"This is the Kernel indicator. It looks like this when the Kernel is idle." -msgstr "" -"Dit is de Kernel indicator. Het ziet er zo uit als de Kernel niet actief is." - -#: notebook/static/notebook/js/tour.js:103 -msgid "The Kernel indicator looks like this when the Kernel is busy." -msgstr "De Kernel indicator ziet er als volgt uit wanneer de Kernel bezig is." - -#: notebook/static/notebook/js/tour.js:107 -msgid "Interrupting the Kernel" -msgstr "De kernel onderbreken" - -#: notebook/static/notebook/js/tour.js:109 -msgid "To cancel a computation in progress, you can click here." -msgstr "Als u een actieve berekening wilt annuleren, kan u hier klikken." - -#: notebook/static/notebook/js/tour.js:114 -msgid "Notification Area" -msgstr "Systeemvak" - -#: notebook/static/notebook/js/tour.js:115 -msgid "" -"Messages in response to user actions (Save, Interrupt, etc.) appear here." -msgstr "" -"Berichten in reactie op acties van gebruikers (Opslaan, Onderbreken, enz.) " -"worden hier weergegeven." - -#: notebook/static/notebook/js/tour.js:117 -msgid "End of Tour" -msgstr "Einde van de Tour" - -#: notebook/static/notebook/js/tour.js:120 -msgid "This concludes the Jupyter Notebook User Interface Tour." -msgstr "Dit concludeert de Jupyter Notebook User Interface Rondleiding." - -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32 -msgid "Edit Attachments" -msgstr "Bijlagen bewerken" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:19 -msgid "Cell" -msgstr "Cel" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:29 -#: notebook/static/notebook/js/celltoolbarpresets/default.js:47 -msgid "Edit Metadata" -msgstr "Metagegevens bewerken" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22 -msgid "Custom" -msgstr "Aangepaste" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32 -msgid "Set the MIME type of the raw cell:" -msgstr "Stel het MIME-type van de raw cel in:" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40 -msgid "Raw Cell MIME Type" -msgstr "Raw Cell MIME-type" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74 -msgid "Raw NBConvert Format" -msgstr "Raw NBConvert-indeling" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81 -msgid "Raw Cell Format" -msgstr "Raw-celnotatie" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15 -msgid "Slide" -msgstr "Dia" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:16 -msgid "Sub-Slide" -msgstr "Subdia" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:17 -msgid "Fragment" -msgstr "Fragment" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:18 -msgid "Skip" -msgstr "Overslaan" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:19 -msgid "Notes" -msgstr "Notities" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35 -msgid "Slide Type" -msgstr "Diatype" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41 -msgid "Slideshow" -msgstr "Diavoorstelling" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:133 -msgid "Add tag" -msgstr "Tag toevoegen" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163 -msgid "" -"Edit the list of tags below. All whitespace is treated as tag separators." -msgstr "" -"Bewerk de onderstaande lijst met tags. Alle witruimte wordt behandeld als " -"tagscheidingstekens." - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172 -msgid "Edit the tags" -msgstr "De tags bewerken" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186 -msgid "Edit Tags" -msgstr "Tags bewerken" - -#: notebook/static/tree/js/kernellist.js:86 -#: notebook/static/tree/js/terminallist.js:105 -msgid "Shutdown" -msgstr "Afsluiten" - -#: notebook/static/tree/js/newnotebook.js:70 -#, python-format -msgid "Create a new notebook with %s" -msgstr "Een nieuw notebook maken met %s" - -#: notebook/static/tree/js/newnotebook.js:101 -msgid "An error occurred while creating a new notebook." -msgstr "" -"Er is een fout opgetreden tijdens het maken van een nieuw notebook." - -#: notebook/static/tree/js/notebooklist.js:122 -msgid "Creating File Failed" -msgstr "Bestand maken is mislukt" - -#: notebook/static/tree/js/notebooklist.js:124 -msgid "An error occurred while creating a new file." -msgstr "Er is een fout opgetreden tijdens het maken van een nieuw bestand." - -#: notebook/static/tree/js/notebooklist.js:142 -msgid "Creating Folder Failed" -msgstr "Map maken is mislukt" - -#: notebook/static/tree/js/notebooklist.js:144 -msgid "An error occurred while creating a new folder." -msgstr "Er is een fout opgetreden tijdens het maken van een nieuwe map." - -#: notebook/static/tree/js/notebooklist.js:271 -msgid "Failed to read file" -msgstr "Bestand niet kunnen worden gelezen" - -#: notebook/static/tree/js/notebooklist.js:272 -#, python-format -msgid "Failed to read file %s" -msgstr "Bestand %s niet kunnen lezen" - -#: notebook/static/tree/js/notebooklist.js:283 -#, python-format -msgid "The file size is %d MB. Do you still want to upload it?" -msgstr "De bestandsgrootte is %d MB. Wil je het nog steeds uploaden?" - -#: notebook/static/tree/js/notebooklist.js:286 -msgid "Large file size warning" -msgstr "Waarschuwing voor grote bestandsgrootte" - -#: notebook/static/tree/js/notebooklist.js:355 -msgid "Server error: " -msgstr "Serverfout: " - -#: notebook/static/tree/js/notebooklist.js:390 -msgid "The notebook list is empty." -msgstr "De lijst met notebooks is leeg." - -#: notebook/static/tree/js/notebooklist.js:463 -msgid "Click here to rename, delete, etc." -msgstr "Klik hier om de naam te wijzigen, te verwijderen, enz." - -#: notebook/static/tree/js/notebooklist.js:503 -msgid "Running" -msgstr "Actieve Processen" - -#: notebook/static/tree/js/notebooklist.js:835 -msgid "Enter a new file name:" -msgstr "Voer een nieuwe bestandsnaam in:" - -#: notebook/static/tree/js/notebooklist.js:836 -msgid "Enter a new directory name:" -msgstr "Voer een nieuwe mapnaam in:" - -#: notebook/static/tree/js/notebooklist.js:838 -msgid "Enter a new name:" -msgstr "Voer een nieuwe naam in:" - -#: notebook/static/tree/js/notebooklist.js:843 -msgid "Rename file" -msgstr "Naamvan het bestand wijzigen" - -#: notebook/static/tree/js/notebooklist.js:844 -msgid "Rename directory" -msgstr "Naamvan naam wijzigen" - -#: notebook/static/tree/js/notebooklist.js:845 -msgid "Rename notebook" -msgstr "De naam van notebook wijzigen" - -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Move" -msgstr "Verplaatsen" - -#: notebook/static/tree/js/notebooklist.js:875 -msgid "An error occurred while renaming \"%1$s\" to \"%2$s\"." -msgstr "Er is een fout opgetreden bij het hernoemen van \"%1$s\" naar \"%2$s\"." - -#: notebook/static/tree/js/notebooklist.js:878 -msgid "Rename Failed" -msgstr "Naam wijzigen Van mislukt" - -#: notebook/static/tree/js/notebooklist.js:927 -#, python-format -msgid "Enter a new destination directory path for this item:" -msgid_plural "Enter a new destination directory path for these %d items:" -msgstr[0] "Voer een nieuw bestemmingsmap-pad in voor dit item:" -msgstr[1] "Voer een nieuw bestemmingsmap-pad in voor deze %d items:" - -#: notebook/static/tree/js/notebooklist.js:940 -#, python-format -msgid "Move an Item" -msgid_plural "Move %d Items" -msgstr[0] "Een item verplaatsen" -msgstr[1] "%d objecten verplaatsen" - -#: notebook/static/tree/js/notebooklist.js:959 -msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"." -msgstr "" -"Er is een fout opgetreden tijdens het verplaatsen van \"%1$s\" van \"%2$s\" " -"naar \"%3$s\"." - -#: notebook/static/tree/js/notebooklist.js:961 -msgid "Move Failed" -msgstr "Verplaatsen mislukt" - -#: notebook/static/tree/js/notebooklist.js:1007 -#, python-format -msgid "Are you sure you want to permanently delete: \"%s\"?" -msgid_plural "" -"Are you sure you want to permanently delete the %d files or folders " -"selected?" -msgstr[0] "Weet u zeker dat u het volgende definitief wilt verwijderen: \"%s\"?" -msgstr[1] "" -"Weet u zeker dat u de geselecteerde %d bestanden of mappen permanent wilt " -"verwijderen?" - -#: notebook/static/tree/js/notebooklist.js:1035 -#, python-format -msgid "An error occurred while deleting \"%s\"." -msgstr "Er is een fout opgetreden tijdens het verwijderen van \"%s\"." - -#: notebook/static/tree/js/notebooklist.js:1037 -msgid "Delete Failed" -msgstr "Verwijderen mislukt" - -#: notebook/static/tree/js/notebooklist.js:1078 -#, python-format -msgid "Are you sure you want to duplicate: \"%s\"?" -msgid_plural "Are you sure you want to duplicate the %d files selected?" -msgstr[0] "Weet u zeker dat u wilt dupliceren: \"%s\"?" -msgstr[1] "Weet u zeker dat u de geselecteerde %d bestanden wilt dupliceren?" - -#: notebook/static/tree/js/notebooklist.js:1088 -msgid "Duplicate" -msgstr "Dupliceren" - -#: notebook/static/tree/js/notebooklist.js:1102 -#, python-format -msgid "An error occurred while duplicating \"%s\"." -msgstr "Er is een fout opgetreden tijdens het dupliceren van \"%s\"." - -#: notebook/static/tree/js/notebooklist.js:1104 -msgid "Duplicate Failed" -msgstr "Dupliceren is mislukt" - -#: notebook/static/tree/js/notebooklist.js:1323 -msgid "Upload" -msgstr "Uploaden" - -#: notebook/static/tree/js/notebooklist.js:1332 -msgid "Invalid file name" -msgstr "Ongeldige bestandsnaam" - -#: notebook/static/tree/js/notebooklist.js:1333 -msgid "File names must be at least one character and not start with a period" -msgstr "" -"Bestandsnamen moeten ten minste één teken zijn en niet beginnen met een " -"periode" - -#: notebook/static/tree/js/notebooklist.js:1362 -msgid "Cannot upload invalid Notebook" -msgstr "Kan ongeldig notebook niet uploaden" - -#: notebook/static/tree/js/notebooklist.js:1395 -#, python-format -msgid "There is already a file named \"%s\". Do you want to replace it?" -msgstr "Er is al een bestand met de naam \"%s\". Wilt u het vervangen?" - -#: notebook/static/tree/js/notebooklist.js:1397 -msgid "Replace file" -msgstr "Bestand vervangen" diff --git a/notebook/i18n/nl/LC_MESSAGES/nbui.mo b/notebook/i18n/nl/LC_MESSAGES/nbui.mo deleted file mode 100644 index 3e762e8b1..000000000 Binary files a/notebook/i18n/nl/LC_MESSAGES/nbui.mo and /dev/null differ diff --git a/notebook/i18n/nl/LC_MESSAGES/nbui.po b/notebook/i18n/nl/LC_MESSAGES/nbui.po deleted file mode 100644 index 69e42090c..000000000 --- a/notebook/i18n/nl/LC_MESSAGES/nbui.po +++ /dev/null @@ -1,746 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-07 12:48-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "U vraagt een pagina die niet bestaat!" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "huidige modus" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "Bestand" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "Nieuw" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "Opslaan" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "Hernoemen" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "Downloaden" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "Bewerken" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "Vinden" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "Zoeken en vervangen" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "Sleutelkaart" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "Standaard" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "Sublime Tekst" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "Bekijken" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "" -"Het logo en de titel van het notebook weergeven/verbergen (boven " -"menubalk)" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "Koptekst in- of uitschakelen" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "Regelnummers in- of uitschakelen" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "Taal" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "De fout was:" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "Wachtwoord of token:" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "Wachtwoord:" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "Aanmelden" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "Geen login beschikbaar, u zou deze pagina niet moeten zien." - -#: notebook/templates/logout.html:24 -#, python-format -msgid "Proceed to the dashboard" -msgstr "Ga naar het dashboard " - -#: notebook/templates/logout.html:26 -#, python-format -msgid "Proceed to the login page" -msgstr "Ga naar de login pagina" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "Menu" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "Kernel" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "Dit notebook is alleen-lezen" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "Nieuw notebook" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "Opent een nieuw venster met de dashboardweergave" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "Open..." - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "" -"Een kopie van de inhoud van dit notebook openen en een nieuwe kernel " -"starten" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "Maak een kopie..." - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "Hernoemen..." - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "Opslaan en Checkpoint" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "Terugkeren naar Checkpoint" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "Afdrukvoorbeeld" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "Download als" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "Notebook (.ipynb)" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "Script" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "HTML (.html)" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "Markdown (.md)" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "reST (.rst)" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "LaTeX (.tex)" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "PDF via LaTeX (.pdf)" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "Implementeren als" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "Vertrouwen op de uitvoer van dit notebook" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "Notebook vertrouwen" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "De kernel van deze notebook afsluiten en dit venster sluiten" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "Sluiten en Halt" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "Cellen knippen" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "Cellen kopiëren" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "Cellen boven plakken" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "Cellen eronder plakken" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "Cellen plakken en vervangen" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "Cellen verwijderen" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "Verwijdercellen ongedaan maken" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "Cel splitsen" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "Cel boven samenvoegen" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "Cel eronder samenvoegen" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "Cel omhoog verplaatsen" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "Cel omlaag verplaatsen" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "Metagegevens van notebook bewerken" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "Zoeken en vervangen" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "Celbijlagen knippen" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "Celbijlagen kopiëren" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "Celbijlagen plakken" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "Afbeelding invoegen" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "De actiepictogrammen weergeven/verbergen (onder menubalk)" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "Werkbalk in- en uitschakelen" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "Lijnnummers weergeven/verbergen in cellen" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "Celwerkbalk" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "Invoegen" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "Een lege codecel boven de actieve cel invoegen" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "Cel boven invoegen" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "Een lege codecel onder de actieve cel invoegen" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "Cel eronder invoegen" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "Cel" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "Deze cel uitvoeren en cursor naar de volgende cel verplaatsen" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "Cellen uitvoeren" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "Voer deze cel uit en selecteer de cel eronder" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "Cellen uitvoeren en de cel eronder selecteren" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "Voer deze cel uit en voeg een cel toe" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "Cellen uitvoeren en voeg een cel toe" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "Alle cellen in het notebook uitvoeren" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "Alles uitvoeren" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "Alle cellen boven (maar niet inclusief) deze cel uitvoeren" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "All cellen hierboven uitvoeren" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "Voer deze cel en alle cellen eronder uit." - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "Voer alles eronder uit" - -#: notebook/templates/notebook.html:205 -msgid "" -"All cells in the notebook have a cell type. By default, new cells are " -"created as 'Code' cells" -msgstr "" -"Alle cellen in het notebook hebben een celtype. Standaard worden nieuwe " -"cellen gemaakt als 'Code'-cellen" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "Celtype" - -#: notebook/templates/notebook.html:209 -msgid "" -"Contents will be sent to the kernel for execution, and output will display " -"in the footer of cell" -msgstr "" -"Inhoud wordt verzonden naar de kernel voor uitvoering, en de uitvoer wordt " -"weergegeven in de voettekst van de cel" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "Inhoud wordt weergegeven als HTML en dient als verklarende tekst" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "De inhoud zal niet worden gewijzigd door nbconvert" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "Raw NBConvert" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "Huidige uitvoer" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "De uitvoer van de huidige cel verbergen/weergeven" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "In- en uitschakelen" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "De uitvoer van de huidige cel scrollen" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "Scrollen in- en uitschakelen" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "De uitvoer van de huidige cel wissen" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "Wissen" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "Alle uitvoer" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "De uitvoer van alle cellen verbergen/weergeven" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "Door de uitvoer van alle cellen scrollen" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "De uitvoer van alle cellen wissen" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "Toetsenbordinterruptie (Ctrl-C) naar de kernel verzenden" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "Onderbreken" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "De kernel opnieuw starten" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "Opnieuw starten" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "Start de kernel opnieuw en schakel alle uitvoer uit" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "Uitvoer opnieuw starten en wissen" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "Start de kernel opnieuw en voer notebook opnieuw uit" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "Alles opnieuw starten en uitvoeren" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "Opnieuw verbinding maken met de kernel" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "Sluit" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "Kernel wijzigen" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "Help" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "Een snelle rondleiding door de gebruikersinterface van de notebook" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "Gebruikersinterfacetour" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "Hiermee opent u een tooltop met alle sneltoetsen" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "Sneltoetsen" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "Hiermee opent u een dialoogvenster waarmee u sneltoetsen bewerken" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "Sneltoetsen bewerken" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "Help voor notebooks" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "Opent in een nieuw venster" - -#: notebook/templates/notebook.html:319 -msgid "About Jupyter Notebook" -msgstr "Over Jupyter Notebook" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "Over" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "Jupyter Notebook vereist JavaScript." - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "Schakel het in om door te gaan. " - -#: notebook/templates/page.html:121 -msgid "dashboard" -msgstr "Dashboard" - -#: notebook/templates/page.html:132 -msgid "Logout" -msgstr "Logout" - -#: notebook/templates/page.html:134 -msgid "Login" -msgstr "Login" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "Bestanden" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "Actieve processen" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "Clusters" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "Selecteer items om acties op uit te voeren." - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "Duplicaat geselecteerd" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "Dupliceer" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "Naam wijzigen van geselecteerde" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "Verplaats geselecteerde" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "Verplaatsen" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "Download geselecteerde" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "Geselecteerde notebook(s) afsluiten" - -#: notebook/templates/notebook.html:278 notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "Afsluiten" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "Geef geselecteerde weer" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "Bewerk geselecteerde" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "Verwijder geselecteerde" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "Klik hier om te zoeken naar een bestand dat u wilt uploaden." - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "Uploaden" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "Tekstbestand" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "Map" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "Terminal" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "Terminals Niet Beschikbaar" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "Notebook-lijst vernieuwen" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "Selecteer Alles / Geen" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "Selecteer..." - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "Alle Mappen Selecteren" - -#: notebook/templates/tree.html:98 -msgid "Folders" -msgstr "Mappen" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "Alle Notebooks Selecteren" - -#: notebook/templates/tree.html:99 -msgid "All Notebooks" -msgstr "Alle notebooks" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "Actieve Notebooks Selecteren" - -#: notebook/templates/tree.html:100 -msgid "Running" -msgstr "Actieve Processen" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "Alle Bestanden Selecteren" - -#: notebook/templates/tree.html:101 -msgid "Files" -msgstr "Bestanden" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "Laatst gewijzigd" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "Naam" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "Momenteel actieve Jupyter processen" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "Actieve processen lijst vernieuwen" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "Er zijn geen terminals actief." - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "Terminals zijn niet beschikbaar." - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "Notebooks" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "Er worden geen notebooks uitgevoerd." - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "Clusters tabblad wordt nu geleverd door IPython parallel." - -#: notebook/templates/tree.html:179 -msgid "" -"See 'IPython " -"parallel' for installation details." -msgstr "" -"Zie 'IPython " -"parallel' voor installatiegegevens." diff --git a/notebook/i18n/nl/LC_MESSAGES/notebook.mo b/notebook/i18n/nl/LC_MESSAGES/notebook.mo deleted file mode 100644 index 404e443fe..000000000 Binary files a/notebook/i18n/nl/LC_MESSAGES/notebook.mo and /dev/null differ diff --git a/notebook/i18n/nl/LC_MESSAGES/notebook.po b/notebook/i18n/nl/LC_MESSAGES/notebook.po deleted file mode 100644 index daa6ce7d5..000000000 --- a/notebook/i18n/nl/LC_MESSAGES/notebook.po +++ /dev/null @@ -1,607 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-08 21:52-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/notebookapp.py:53 -msgid "The Jupyter Notebook requires tornado >= 4.0" -msgstr "De Jupyter Notebook vereist tornado >= 4.0" - -#: notebook/notebookapp.py:57 -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "De Jupyter Notebook vereist tornado >= 4.0, maar je hebt < 1.1.0" - -#: notebook/notebookapp.py:59 -#, python-format -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have %s" -msgstr "De Jupyter Notebook vereist tornado >= 4.0, maar je hebt %s" - -#: notebook/notebookapp.py:209 -msgid "The `ignore_minified_js` flag is deprecated and no longer works." -msgstr "De vlag 'ignore_minified_js' is afgeschaft en werkt niet meer." - -#: notebook/notebookapp.py:210 -#, python-format -msgid "" -"Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "" -"U ook '%s' gebruiken bij het werken aan de Javascript van de notebook en " -"LESS" - -#: notebook/notebookapp.py:211 -msgid "" -"The `ignore_minified_js` flag is deprecated and will be removed in Notebook " -"6.0" -msgstr "" -"De vlag 'ignore_minified_js' wordt afgeschaft en wordt verwijderd in " -"Notebook 6.0" - -#: notebook/notebookapp.py:389 -msgid "List currently running notebook servers." -msgstr "Lijst met momenteel draaiende notebookservers." - -#: notebook/notebookapp.py:393 -msgid "Produce machine-readable JSON output." -msgstr "Productie computer-leesbare JSON-uitvoer." - -#: notebook/notebookapp.py:397 -msgid "" -"If True, each line of output will be a JSON object with the details from the" -" server info file." -msgstr "" -"Als dit True is, zal elke uitvoerregel een JSON-object worden met de details uit het " -"serverinfobestand." - -#: notebook/notebookapp.py:402 -msgid "Currently running servers:" -msgstr "Momenteel draaiende servers:" - -#: notebook/notebookapp.py:419 -msgid "Don't open the notebook in a browser after startup." -msgstr "Open het notebook niet in een browser na het opstarten." - -#: notebook/notebookapp.py:423 -msgid "" -"DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "" -"UITGESCHAKELD: gebruik %pylab of %matplotlib in het notebook om " -"matplotlib in te schakelen." - -#: notebook/notebookapp.py:439 -msgid "Allow the notebook to be run from root user." -msgstr "Sta toe dat het notebook vanaf de root user kan worden uitgevoerd." - -#: notebook/notebookapp.py:470 -msgid "" -"The Jupyter HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client." -msgstr "" -"De Jupyter HTML Notebook.\n" -" \n" -"Hiermee wordt een op Tornado gebaseerde HTML-notebookserver gelanceerd die een HTML5/Javascript-laptopclient bedient." - -#: notebook/notebookapp.py:509 -msgid "" -"Deprecated: Use minified JS file or not, mainly use during dev to avoid JS " -"recompilation" -msgstr "" -"Afgeschaft: Gebruik minified JS-bestand of niet, voornamelijk gebruiken " -"tijdens dev om JS recompilatie te voorkomen" - -#: notebook/notebookapp.py:540 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "De access-control-allow-credentials instellen: true header" - -#: notebook/notebookapp.py:544 -msgid "Whether to allow the user to run the notebook as root." -msgstr "Of de gebruiker het notebook als root mag activeren." - -#: notebook/notebookapp.py:548 -msgid "The default URL to redirect to from `/`" -msgstr "De standaard-URL om naar '/' te leiden" - -#: notebook/notebookapp.py:552 -msgid "The IP address the notebook server will listen on." -msgstr "Het IP-adres waar de notebookserver op geactiveerd wordt." - -#: notebook/notebookapp.py:565 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "" -"Kan niet binden aan localhost, met 127.0.0.1 als standaardip\n" -"%s" - -#: notebook/notebookapp.py:579 -msgid "The port the notebook server will listen on." -msgstr "De port waarop de notebookserver geactiveerd wordt." - -#: notebook/notebookapp.py:583 -msgid "" -"The number of additional ports to try if the specified port is not " -"available." -msgstr "" -"Het aantal extra ports dat moet worden geprobeerd als de opgegeven port " -"niet beschikbaar is." - -#: notebook/notebookapp.py:587 -msgid "The full path to an SSL/TLS certificate file." -msgstr "Het volledige pad naar een SSL/TLS-certificaatbestand." - -#: notebook/notebookapp.py:591 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "" -"Het volledige pad naar een privésleutelbestand voor gebruik met SSL/TLS." - -#: notebook/notebookapp.py:595 -msgid "" -"The full path to a certificate authority certificate for SSL/TLS client " -"authentication." -msgstr "" -"Het volledige pad naar een certificaat van certificaatautoriteit voor " -"SSL/TLS-clientverificatie." - -#: notebook/notebookapp.py:599 -msgid "The file where the cookie secret is stored." -msgstr "Het bestand waarin het cookiegeheim wordt opgeslagen." - -#: notebook/notebookapp.py:628 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "Cookiegeheim voor notebookserver schrijven naar %s" - -#: notebook/notebookapp.py:635 -#, python-format -msgid "Could not set permissions on %s" -msgstr "Kan geen machtigingen instellen op %s" - -#: notebook/notebookapp.py:640 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "" -"Token wordt gebruikt voor het verifiëren van eerste verbindingen met de server.\n" -"\n" -"Wanneer er geen wachtwoord is ingeschakeld,\n" -" de standaardinstelling is het genereren van een nieuwe, willekeurige token.\n" -"\n" -"Als u een lege tekenreeks instelt, wordt de verificatie helemaal uitgeschakeld, wat niet wordt aanbevolen.\n" -" " - -#: notebook/notebookapp.py:650 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" -"Eenmalige token die wordt gebruikt voor het openen van een browser.\n" -" Eenmaal gebruikt, kan dit token niet opnieuw worden gebruikt.\n" -" " - -#: notebook/notebookapp.py:726 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" -"Geef op waar u het notebook moet openen bij het opstarten. Dit is de\n" -" 'nieuw' argument doorgegeven aan de standaard bibliotheek methode 'webbrowser.open'.\n" -" Het gedrag is niet gegarandeerd, maar is afhankelijk van browserondersteuning. Geldig\n" -" waarden zijn:\n" -" 2 opent een nieuw tabblad,\n" -" 1 opent een nieuw venster,\n" -" 0 wordt geopend in een bestaand venster.\n" -" Zie de documentatie 'webbrowser.open' voor meer informatie.\n" -" " - -#: notebook/notebookapp.py:737 -msgid "DEPRECATED, use tornado_settings" -msgstr "DEPRECATED, gebruik tornado_settings" - -#: notebook/notebookapp.py:742 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "" -"\n" -"webapp_settings is deprecated, gebruik tornado_settings.\n" - -#: notebook/notebookapp.py:746 -msgid "" -"Supply overrides for the tornado.web.Application that the Jupyter notebook " -"uses." -msgstr "" -"Geef extra instellingen voor de tornado.web.Application die gebruikt wordt door de " -" Jupyter notebook." - -#: notebook/notebookapp.py:750 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" -"\n" -"Stel de tornadocompressieopties in voor websocketverbindingen.\n" -"\n" -"Deze waarde wordt geretourneerd van :meth:'WebSocketHandler.get_compression_options'.\n" -" Geen (standaard) schakelt compressie uit.\n" -" Een dict (zelfs een lege) zal compressie mogelijk maken.\n" -"\n" -"Zie de tornadodocumenten voor WebSocketHandler.get_compression_options voor meer informatie.\n" -" " - -#: notebook/notebookapp.py:761 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" -"Supply overrides voor terminado. Ondersteunt momenteel alleen een " -"\"shell_command\"." - -#: notebook/notebookapp.py:764 -msgid "" -"Extra keyword arguments to pass to `set_secure_cookie`. See tornado's " -"set_secure_cookie docs for details." -msgstr "" -"Extra trefwoordargumenten om door te geven aan 'set_secure_cookie'. Zie " -"tornado's set_secure_cookie documenten voor meer informatie." - -#: notebook/notebookapp.py:768 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" -"SSL-opties leveren voor de tornado HTTPServer.\n" -" Zie de tornado docs voor meer informatie." - -#: notebook/notebookapp.py:772 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "" -"Vul extra argumenten aan die zullen worden doorgegeven aan de Jinja environment." - -#: notebook/notebookapp.py:776 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "Extra variabelen om aan te vullen aan de jinja-sjablonen bij het renderen." - -#: notebook/notebookapp.py:812 -msgid "DEPRECATED use base_url" -msgstr "DEPRECATED gebruik base_url" - -#: notebook/notebookapp.py:816 -msgid "base_project_url is deprecated, use base_url" -msgstr "base_project_url is deprecated, gebruik base_url" - -#: notebook/notebookapp.py:832 -msgid "Path to search for custom.js, css" -msgstr "Pad om te zoeken naar custom.js, css" - -#: notebook/notebookapp.py:844 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "" -"Extra paden om te zoeken voor het activeren van jinja-sjablonen.\n" -"\n" -"Kan worden gebruikt om sjablonen van notebook.templates te overschrijven." - -#: notebook/notebookapp.py:855 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "extra paden om te zoeken naar Javascript-notebookextensies" - -#: notebook/notebookapp.py:900 -#, python-format -msgid "Using MathJax: %s" -msgstr "MathJax gebruiken: %s" - -#: notebook/notebookapp.py:903 -msgid "The MathJax.js configuration file that is to be used." -msgstr "Het configuratiebestand MathJax.js dat moet worden gebruikt." - -#: notebook/notebookapp.py:908 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "MathJax-configuratiebestand gebruiken: %s" - -#: notebook/notebookapp.py:914 -msgid "The notebook manager class to use." -msgstr "De notebook manager klasse te gebruiken." - -#: notebook/notebookapp.py:920 -msgid "The kernel manager class to use." -msgstr "De kernel manager klasse om te gebruiken." - -#: notebook/notebookapp.py:926 -msgid "The session manager class to use." -msgstr "De sessie manager klasse die u gebruiken." - -#: notebook/notebookapp.py:932 -msgid "The config manager class to use" -msgstr "De config manager klasse te gebruiken" - -#: notebook/notebookapp.py:953 -msgid "The login handler class to use." -msgstr "De login handler klasse te gebruiken." - -#: notebook/notebookapp.py:960 -msgid "The logout handler class to use." -msgstr "De afmeld handler klasse die u wilt gebruiken." - -#: notebook/notebookapp.py:964 -msgid "" -"Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-" -"Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if " -"the proxy handles SSL" -msgstr "" -"X-Scheme/X-Forwarded-Proto en X-Real-Ip/X-Forwarded-For headerssent door de " -"upstream reverse proxy al dan niet vertrouwen. Noodzakelijk als de proxy SSL" -" verwerkt" - -#: notebook/notebookapp.py:976 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "" -"\n" -"UITGESCHAKELD: gebruik %pylab of %matplotlib in het notebook om matplotlib in te schakelen.\n" -" " - -#: notebook/notebookapp.py:988 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "" -"Ondersteuning voor het opgeven van --pylab op de opdrachtregel is " -"verwijderd." - -#: notebook/notebookapp.py:990 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "Gebruik '%pylab{0}' of '%matplotlib{0}' in het notebook zelf." - -#: notebook/notebookapp.py:995 -msgid "The directory to use for notebooks and kernels." -msgstr "De map die u wilt gebruiken voor notebooks en kernels." - -#: notebook/notebookapp.py:1018 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "Geen dergelijke notebook dir: '%r'" - -#: notebook/notebookapp.py:1031 -msgid "DEPRECATED use the nbserver_extensions dict instead" -msgstr "DEPRECATED gebruikt in plaats daarvan de nbserver_extensions dict" - -#: notebook/notebookapp.py:1036 -msgid "server_extensions is deprecated, use nbserver_extensions" -msgstr "server_extensions is afgeschaft, gebruik nbserver_extensions" - -#: notebook/notebookapp.py:1040 -msgid "" -"Dict of Python modules to load as notebook server extensions.Entry values " -"can be used to enable and disable the loading ofthe extensions. The " -"extensions will be loaded in alphabetical order." -msgstr "" -"Dict van Python-modules te laden als notebook server extensies. " -"Invoerwaarden kunnen worden gebruikt om het laden van de extensies in en uit" -" te schakelen. De extensies worden in alfabetische volgorde geladen." - -#: notebook/notebookapp.py:1049 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "Exceptions opnieuw weergeven die geraised waren tijdens het laden van" -" de server-extensies?" - -#: notebook/notebookapp.py:1052 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" -"(msgs/sec)\n" -" Maximale ratio waarmee berichten op iopub kunnen worden verzonden voordat ze\n" -" worden beperkt." - -#: notebook/notebookapp.py:1056 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" -"(bytes/sec)\n" -" Maximale ratio waarmee streamoutput op iopub kan worden verzonden voordat ze\n" -" worden beperkt." - -#: notebook/notebookapp.py:1060 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "" -"(sec) Tijdvenster gebruikt om \n" -" de limieten voor het verzenden van berichten en de gegevenssnelheiden te" -" controleren." - -#: notebook/notebookapp.py:1071 -#, python-format -msgid "No such file or directory: %s" -msgstr "Geen dergelijk bestand of map: %s" - -#: notebook/notebookapp.py:1141 -msgid "Notebook servers are configured to only be run with a password." -msgstr "" -"Notebookservers zijn geconfigureerd om alleen met een wachtwoord te worden " -"uitgevoerd." - -#: notebook/notebookapp.py:1142 -msgid "Hint: run the following command to set a password" -msgstr "Tip: voer de volgende opdracht uit om een wachtwoord in te stellen" - -#: notebook/notebookapp.py:1143 -msgid "\t$ python -m notebook.auth password" -msgstr "\t$ python -m notebook.auth wachtwoord" - -#: notebook/notebookapp.py:1181 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "De port %i is al in gebruik, proberen een andere port." - -#: notebook/notebookapp.py:1184 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "Toestemming om te luisteren op port %i geweigerd" - -#: notebook/notebookapp.py:1193 -msgid "" -"ERROR: the notebook server could not be started because no available port " -"could be found." -msgstr "" -"FOUT: de notebookserver kan niet worden gestart omdat er geen beschikbare " -"port kon worden gevonden." - -#: notebook/notebookapp.py:1199 -msgid "[all ip addresses on your system]" -msgstr "[alle IP-adressen op uw systeem]" - -#: notebook/notebookapp.py:1223 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "Terminals niet beschikbaar (fout was %s)" - -#: notebook/notebookapp.py:1259 -msgid "interrupted" -msgstr "onderbroken" - -#: notebook/notebookapp.py:1261 -msgid "y" -msgstr "y" - -#: notebook/notebookapp.py:1262 -msgid "n" -msgstr "n" - -#: notebook/notebookapp.py:1263 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "Deze notebookserver afsluiten (%s/[%s])? " - -#: notebook/notebookapp.py:1269 -msgid "Shutdown confirmed" -msgstr "Afsluiten bevestigd" - -#: notebook/notebookapp.py:1273 -msgid "No answer for 5s:" -msgstr "Geen antwoord voor 5s:" - -#: notebook/notebookapp.py:1274 -msgid "resuming operation..." -msgstr "hervatting van de werking..." - -#: notebook/notebookapp.py:1282 -#, python-format -msgid "received signal %s, stopping" -msgstr "ontvangen signaal %s, stoppen" - -#: notebook/notebookapp.py:1338 -#, python-format -msgid "Error loading server extension %s" -msgstr "Foutladen serverextensie %s" - -#: notebook/notebookapp.py:1369 -#, python-format -msgid "Shutting down %d kernels" -msgstr "%d-kernels afsluiten" - -#: notebook/notebookapp.py:1375 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "%d actieve kernel" -msgstr[1] "%d actieve kernel" - -#: notebook/notebookapp.py:1379 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"\r" -"%s" -msgstr "" -"De Jupyter Notebook draait op:\n" -"\r" -"%s" - -#: notebook/notebookapp.py:1426 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "" -"Hardlopen als root wordt niet aanbevolen. Gebruik --allow-root te " -"omzeilen." - -#: notebook/notebookapp.py:1432 -msgid "" -"Use Control-C to stop this server and shut down all kernels (twice to skip " -"confirmation)." -msgstr "" -"Gebruik Control-C om deze server te stoppen en sluit alle kernels af (twee " -"keer om bevestiging over te slaan)." - -#: notebook/notebookapp.py:1434 -msgid "" -"Welcome to Project Jupyter! Explore the various tools available and their " -"corresponding documentation. If you are interested in contributing to the " -"platform, please visit the communityresources section at " -"http://jupyter.org/community.html." -msgstr "" -"Welkom bij Project Jupyter! Bekijk de verschillende tools die beschikbaar " -"zijn en de bijbehorende documentatie. Als je geïnteresseerd bent om bij te " -"dragen aan het platform, ga dan naar de communityresources sectie op " -"http://jupyter.org/community.html." - -#: notebook/notebookapp.py:1445 -#, python-format -msgid "No web browser found: %s." -msgstr "Geen webbrowser gevonden: %s." - -#: notebook/notebookapp.py:1450 -#, python-format -msgid "%s does not exist" -msgstr "%s bestaat niet" - -#: notebook/notebookapp.py:1484 -msgid "Interrupted..." -msgstr "Onderbroken..." - -#: notebook/services/contents/filemanager.py:506 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "Notebooks uit lokale map activeren: %s" - -#: notebook/services/contents/manager.py:68 -msgid "Untitled" -msgstr "Naamloos" diff --git a/notebook/i18n/notebook.pot b/notebook/i18n/notebook.pot deleted file mode 100644 index 5437b1b0f..000000000 --- a/notebook/i18n/notebook.pot +++ /dev/null @@ -1,480 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-08 21:52-0500\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" - -#: notebook/notebookapp.py:53 -msgid "The Jupyter Notebook requires tornado >= 4.0" -msgstr "" - -#: notebook/notebookapp.py:57 -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "" - -#: notebook/notebookapp.py:59 -#, python-format -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have %s" -msgstr "" - -#: notebook/notebookapp.py:209 -msgid "The `ignore_minified_js` flag is deprecated and no longer works." -msgstr "" - -#: notebook/notebookapp.py:210 -#, python-format -msgid "Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "" - -#: notebook/notebookapp.py:211 -msgid "The `ignore_minified_js` flag is deprecated and will be removed in Notebook 6.0" -msgstr "" - -#: notebook/notebookapp.py:389 -msgid "List currently running notebook servers." -msgstr "" - -#: notebook/notebookapp.py:393 -msgid "Produce machine-readable JSON output." -msgstr "" - -#: notebook/notebookapp.py:397 -msgid "If True, each line of output will be a JSON object with the details from the server info file." -msgstr "" - -#: notebook/notebookapp.py:402 -msgid "Currently running servers:" -msgstr "" - -#: notebook/notebookapp.py:419 -msgid "Don't open the notebook in a browser after startup." -msgstr "" - -#: notebook/notebookapp.py:423 -msgid "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "" - -#: notebook/notebookapp.py:439 -msgid "Allow the notebook to be run from root user." -msgstr "" - -#: notebook/notebookapp.py:470 -msgid "" -"The Jupyter HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client." -msgstr "" - -#: notebook/notebookapp.py:509 -msgid "Deprecated: Use minified JS file or not, mainly use during dev to avoid JS recompilation" -msgstr "" - -#: notebook/notebookapp.py:540 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "" - -#: notebook/notebookapp.py:544 -msgid "Whether to allow the user to run the notebook as root." -msgstr "" - -#: notebook/notebookapp.py:548 -msgid "The default URL to redirect to from `/`" -msgstr "" - -#: notebook/notebookapp.py:552 -msgid "The IP address the notebook server will listen on." -msgstr "" - -#: notebook/notebookapp.py:565 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "" - -#: notebook/notebookapp.py:579 -msgid "The port the notebook server will listen on." -msgstr "" - -#: notebook/notebookapp.py:583 -msgid "The number of additional ports to try if the specified port is not available." -msgstr "" - -#: notebook/notebookapp.py:587 -msgid "The full path to an SSL/TLS certificate file." -msgstr "" - -#: notebook/notebookapp.py:591 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "" - -#: notebook/notebookapp.py:595 -msgid "The full path to a certificate authority certificate for SSL/TLS client authentication." -msgstr "" - -#: notebook/notebookapp.py:599 -msgid "The file where the cookie secret is stored." -msgstr "" - -#: notebook/notebookapp.py:628 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "" - -#: notebook/notebookapp.py:635 -#, python-format -msgid "Could not set permissions on %s" -msgstr "" - -#: notebook/notebookapp.py:640 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:650 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:726 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:737 -msgid "DEPRECATED, use tornado_settings" -msgstr "" - -#: notebook/notebookapp.py:742 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "" - -#: notebook/notebookapp.py:746 -msgid "Supply overrides for the tornado.web.Application that the Jupyter notebook uses." -msgstr "" - -#: notebook/notebookapp.py:750 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:761 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" - -#: notebook/notebookapp.py:764 -msgid "Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details." -msgstr "" - -#: notebook/notebookapp.py:768 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" - -#: notebook/notebookapp.py:772 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "" - -#: notebook/notebookapp.py:776 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "" - -#: notebook/notebookapp.py:812 -msgid "DEPRECATED use base_url" -msgstr "" - -#: notebook/notebookapp.py:816 -msgid "base_project_url is deprecated, use base_url" -msgstr "" - -#: notebook/notebookapp.py:832 -msgid "Path to search for custom.js, css" -msgstr "" - -#: notebook/notebookapp.py:844 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "" - -#: notebook/notebookapp.py:855 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "" - -#: notebook/notebookapp.py:900 -#, python-format -msgid "Using MathJax: %s" -msgstr "" - -#: notebook/notebookapp.py:903 -msgid "The MathJax.js configuration file that is to be used." -msgstr "" - -#: notebook/notebookapp.py:908 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "" - -#: notebook/notebookapp.py:914 -msgid "The notebook manager class to use." -msgstr "" - -#: notebook/notebookapp.py:920 -msgid "The kernel manager class to use." -msgstr "" - -#: notebook/notebookapp.py:926 -msgid "The session manager class to use." -msgstr "" - -#: notebook/notebookapp.py:932 -msgid "The config manager class to use" -msgstr "" - -#: notebook/notebookapp.py:953 -msgid "The login handler class to use." -msgstr "" - -#: notebook/notebookapp.py:960 -msgid "The logout handler class to use." -msgstr "" - -#: notebook/notebookapp.py:964 -msgid "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL" -msgstr "" - -#: notebook/notebookapp.py:976 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:988 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "" - -#: notebook/notebookapp.py:990 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "" - -#: notebook/notebookapp.py:995 -msgid "The directory to use for notebooks and kernels." -msgstr "" - -#: notebook/notebookapp.py:1018 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "" - -#: notebook/notebookapp.py:1031 -msgid "DEPRECATED use the nbserver_extensions dict instead" -msgstr "" - -#: notebook/notebookapp.py:1036 -msgid "server_extensions is deprecated, use nbserver_extensions" -msgstr "" - -#: notebook/notebookapp.py:1040 -msgid "Dict of Python modules to load as notebook server extensions.Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order." -msgstr "" - -#: notebook/notebookapp.py:1049 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "" - -#: notebook/notebookapp.py:1052 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/notebookapp.py:1056 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/notebookapp.py:1060 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "" - -#: notebook/notebookapp.py:1071 -#, python-format -msgid "No such file or directory: %s" -msgstr "" - -#: notebook/notebookapp.py:1141 -msgid "Notebook servers are configured to only be run with a password." -msgstr "" - -#: notebook/notebookapp.py:1142 -msgid "Hint: run the following command to set a password" -msgstr "" - -#: notebook/notebookapp.py:1143 -msgid "\t$ python -m notebook.auth password" -msgstr "" - -#: notebook/notebookapp.py:1181 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "" - -#: notebook/notebookapp.py:1184 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "" - -#: notebook/notebookapp.py:1193 -msgid "ERROR: the notebook server could not be started because no available port could be found." -msgstr "" - -#: notebook/notebookapp.py:1199 -msgid "[all ip addresses on your system]" -msgstr "" - -#: notebook/notebookapp.py:1223 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "" - -#: notebook/notebookapp.py:1259 -msgid "interrupted" -msgstr "" - -#: notebook/notebookapp.py:1261 -msgid "y" -msgstr "" - -#: notebook/notebookapp.py:1262 -msgid "n" -msgstr "" - -#: notebook/notebookapp.py:1263 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "" - -#: notebook/notebookapp.py:1269 -msgid "Shutdown confirmed" -msgstr "" - -#: notebook/notebookapp.py:1273 -msgid "No answer for 5s:" -msgstr "" - -#: notebook/notebookapp.py:1274 -msgid "resuming operation..." -msgstr "" - -#: notebook/notebookapp.py:1282 -#, python-format -msgid "received signal %s, stopping" -msgstr "" - -#: notebook/notebookapp.py:1338 -#, python-format -msgid "Error loading server extension %s" -msgstr "" - -#: notebook/notebookapp.py:1369 -#, python-format -msgid "Shutting down %d kernels" -msgstr "" - -#: notebook/notebookapp.py:1375 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "" -msgstr[1] "" - -#: notebook/notebookapp.py:1379 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"\r" -"%s" -msgstr "" - -#: notebook/notebookapp.py:1426 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "" - -#: notebook/notebookapp.py:1432 -msgid "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." -msgstr "" - -#: notebook/notebookapp.py:1434 -msgid "Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at http://jupyter.org/community.html." -msgstr "" - -#: notebook/notebookapp.py:1445 -#, python-format -msgid "No web browser found: %s." -msgstr "" - -#: notebook/notebookapp.py:1450 -#, python-format -msgid "%s does not exist" -msgstr "" - -#: notebook/notebookapp.py:1484 -msgid "Interrupted..." -msgstr "" - -#: notebook/services/contents/filemanager.py:506 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "" - -#: notebook/services/contents/manager.py:68 -msgid "Untitled" -msgstr "" - diff --git a/notebook/i18n/ru_RU/LC_MESSAGES/nbjs.po b/notebook/i18n/ru_RU/LC_MESSAGES/nbjs.po deleted file mode 100644 index 644d2e18b..000000000 --- a/notebook/i18n/ru_RU/LC_MESSAGES/nbjs.po +++ /dev/null @@ -1,2112 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-06-27 14:04-0500\n" -"PO-Revision-Date: 2020-07-09 13:08+0500\n" -"Language-Team: TranslAster \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" -"X-Generator: Poedit 2.3.1\n" -"Last-Translator: Dmitriy Q \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" -"Language: ru_RU\n" - -#: notebook/static/base/js/dialog.js:161 -msgid "Manually edit the JSON below to manipulate the metadata for this cell." -msgstr "" -"Отредактируйте JSON ниже вручную для управления метаданными для этой ячейки." - -#: notebook/static/base/js/dialog.js:163 -msgid "" -"Manually edit the JSON below to manipulate the metadata for this notebook." -msgstr "" -"Отредактируйте JSON ниже вручную для управления метаданными для этого " -"блокнота." - -#: notebook/static/base/js/dialog.js:165 -msgid "" -" We recommend putting custom metadata attributes in an appropriately named " -"substructure, so they don't conflict with those of others." -msgstr "" -" Мы рекомендуем поместить пользовательские атрибуты метаданных в " -"подструктуру с соответствующим именем, чтобы они не конфликтовали с " -"атрибутами других объектов." - -#: notebook/static/base/js/dialog.js:180 -msgid "Edit the metadata" -msgstr "Редактировать метаданные" - -#: notebook/static/base/js/dialog.js:202 -msgid "Edit Notebook Metadata" -msgstr "Редактировать метаданные блокнота" - -#: notebook/static/base/js/dialog.js:204 -msgid "Edit Cell Metadata" -msgstr "Редактировать метаданные ячейки" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/notebook.js:475 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:859 -#: notebook/static/tree/js/notebooklist.js:1418 -msgid "Cancel" -msgstr "Отмена" - -#: notebook/static/base/js/dialog.js:208 -msgid "Edit" -msgstr "Редактировать" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/kernelselector.js:278 -#: notebook/static/notebook/js/mathjaxutils.js:42 -#: notebook/static/notebook/js/notebook.js:469 -#: notebook/static/notebook/js/notificationarea.js:187 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/newnotebook.js:97 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "OK" -msgstr "ОК" - -#: notebook/static/base/js/dialog.js:208 -msgid "Apply" -msgstr "Применить" - -#: notebook/static/base/js/dialog.js:225 -msgid "WARNING: Could not save invalid JSON." -msgstr "ПРЕДУПРЕЖДЕНИЕ: не удалось сохранить недопустимый JSON." - -#: notebook/static/base/js/dialog.js:247 -msgid "There are no attachments for this cell." -msgstr "Для этой ячейки нет никаких вложений." - -#: notebook/static/base/js/dialog.js:250 -msgid "Current cell attachments" -msgstr "Вложения текущей ячейки" - -#: notebook/static/base/js/dialog.js:259 -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:46 -msgid "Attachments" -msgstr "Вложения" - -#: notebook/static/base/js/dialog.js:283 -msgid "Restore" -msgstr "Восстановить" - -#: notebook/static/base/js/dialog.js:293 -#: notebook/static/tree/js/notebooklist.js:1018 -msgid "Delete" -msgstr "Удалить" - -#: notebook/static/base/js/dialog.js:342 notebook/static/base/js/dialog.js:386 -msgid "Edit attachments" -msgstr "Редактировать вложения" - -#: notebook/static/base/js/dialog.js:348 -msgid "Edit Notebook Attachments" -msgstr "Редактировать вложения блокнотов" - -#: notebook/static/base/js/dialog.js:350 -msgid "Edit Cell Attachments" -msgstr "Редактировать вложения ячейки" - -#: notebook/static/base/js/dialog.js:373 -msgid "Select a file to insert." -msgstr "Выберите файл для вставки." - -#: notebook/static/base/js/dialog.js:399 -msgid "Select a file" -msgstr "Выберите файл" - -#: notebook/static/notebook/js/about.js:14 -msgid "You are using Jupyter notebook." -msgstr "Вы используете блокнот Jupyter." - -#: notebook/static/notebook/js/about.js:16 -msgid "The version of the notebook server is: " -msgstr "Версия сервера блокнотов: " - -#: notebook/static/notebook/js/about.js:22 -msgid "The server is running on this version of Python:" -msgstr "Сервер работает на этой версии Python:" - -#: notebook/static/notebook/js/about.js:25 -msgid "Waiting for kernel to be available..." -msgstr "Ожидание доступности ядра..." - -#: notebook/static/notebook/js/about.js:27 -msgid "Server Information:" -msgstr "Информация сервера:" - -#: notebook/static/notebook/js/about.js:29 -msgid "Current Kernel Information:" -msgstr "Информация о текущем ядре:" - -#: notebook/static/notebook/js/about.js:32 -msgid "Could not access sys_info variable for version information." -msgstr "" -"Невозможно получить доступ к переменной sys_info для получения информации о " -"версии." - -#: notebook/static/notebook/js/about.js:34 -msgid "Cannot find sys_info!" -msgstr "Невозможно найти sys_info!" - -#: notebook/static/notebook/js/about.js:38 -msgid "About Jupyter Notebook" -msgstr "О блокноте Jupyter" - -#: notebook/static/notebook/js/about.js:47 -msgid "unable to contact kernel" -msgstr "невозможно связаться с ядром" - -#: notebook/static/notebook/js/actions.js:69 -msgid "toggle rtl layout" -msgstr "переключить макет rtl" - -#: notebook/static/notebook/js/actions.js:70 -msgid "" -"Toggle the screen directionality between left-to-right and right-to-left" -msgstr "Переключение направления экрана между слева направо и справа налево" - -#: notebook/static/notebook/js/actions.js:76 -msgid "edit command mode keyboard shortcuts" -msgstr "редактировать сочетания клавиш командного режима" - -#: notebook/static/notebook/js/actions.js:77 -msgid "Open a dialog to edit the command mode keyboard shortcuts" -msgstr "" -"Откройте диалоговое окно для редактирования сочетаний клавиш командного " -"режима" - -#: notebook/static/notebook/js/actions.js:97 -msgid "restart kernel" -msgstr "перезапуск ядра" - -#: notebook/static/notebook/js/actions.js:98 -msgid "restart the kernel (no confirmation dialog)" -msgstr "перезапуск ядра (диалог подтверждения отсутствует)" - -#: notebook/static/notebook/js/actions.js:106 -msgid "confirm restart kernel" -msgstr "подтвердить перезапуск ядра" - -#: notebook/static/notebook/js/actions.js:107 -msgid "restart the kernel (with dialog)" -msgstr "перезапуск ядра (с диалоговым окном)" - -#: notebook/static/notebook/js/actions.js:113 -msgid "restart kernel and run all cells" -msgstr "перезапуск ядра и запуск всех ячеек" - -#: notebook/static/notebook/js/actions.js:114 -msgid "" -"restart the kernel, then re-run the whole notebook (no confirmation dialog)" -msgstr "" -"перезапустить ядро, а затем перезапустить весь блокнот (диалог подтверждения " -"отсутствует)" - -#: notebook/static/notebook/js/actions.js:120 -msgid "confirm restart kernel and run all cells" -msgstr "подтвердить перезапуск ядра и запуск всех ячеек" - -#: notebook/static/notebook/js/actions.js:121 -msgid "restart the kernel, then re-run the whole notebook (with dialog)" -msgstr "" -"перезапустить ядро, а затем перезапустить весь блокнот (с диалогом " -"подтверждения)" - -#: notebook/static/notebook/js/actions.js:127 -msgid "restart kernel and clear output" -msgstr "перезапуск ядра и очистка вывода" - -#: notebook/static/notebook/js/actions.js:128 -msgid "restart the kernel and clear all output (no confirmation dialog)" -msgstr "" -"перезапустить ядро и очистить все выходные данные (диалог подтверждения " -"отсутствует)" - -#: notebook/static/notebook/js/actions.js:134 -msgid "confirm restart kernel and clear output" -msgstr "подтвердить перезапуск ядра и очистку вывода" - -#: notebook/static/notebook/js/actions.js:135 -msgid "restart the kernel and clear all output (with dialog)" -msgstr "" -"перезапустить ядро и очистить все выходные данные (с диалогом подтверждения)" - -#: notebook/static/notebook/js/actions.js:142 -#: notebook/static/notebook/js/actions.js:143 -msgid "interrupt the kernel" -msgstr "прервать работу ядра" - -#: notebook/static/notebook/js/actions.js:150 -msgid "run cell and select next" -msgstr "запустить ячейку и выбрать следующую" - -#: notebook/static/notebook/js/actions.js:152 -msgid "run cell, select below" -msgstr "запустить ячейку, выбрать ниже" - -#: notebook/static/notebook/js/actions.js:159 -#: notebook/static/notebook/js/actions.js:160 -msgid "run selected cells" -msgstr "запустить выбранные ячейки" - -#: notebook/static/notebook/js/actions.js:167 -#: notebook/static/notebook/js/actions.js:168 -msgid "run cell and insert below" -msgstr "запустить ячейку и вставить ниже" - -#: notebook/static/notebook/js/actions.js:175 -#: notebook/static/notebook/js/actions.js:176 -msgid "run all cells" -msgstr "запуск всех ячеек" - -#: notebook/static/notebook/js/actions.js:183 -#: notebook/static/notebook/js/actions.js:184 -msgid "run all cells above" -msgstr "запуск всех ячеек выше" - -#: notebook/static/notebook/js/actions.js:190 -#: notebook/static/notebook/js/actions.js:191 -msgid "run all cells below" -msgstr "запуск всех ячеек ниже" - -#: notebook/static/notebook/js/actions.js:197 -#: notebook/static/notebook/js/actions.js:198 -msgid "enter command mode" -msgstr "вход в командный режим" - -#: notebook/static/notebook/js/actions.js:205 -#: notebook/static/notebook/js/actions.js:206 -msgid "insert image" -msgstr "вставить изображение" - -#: notebook/static/notebook/js/actions.js:213 -#: notebook/static/notebook/js/actions.js:214 -msgid "cut cell attachments" -msgstr "вырезать вложения ячейки" - -#: notebook/static/notebook/js/actions.js:221 -#: notebook/static/notebook/js/actions.js:222 -msgid "copy cell attachments" -msgstr "копирование вложений ячейки" - -#: notebook/static/notebook/js/actions.js:229 -#: notebook/static/notebook/js/actions.js:230 -msgid "paste cell attachments" -msgstr "вставить вложения ячейки" - -#: notebook/static/notebook/js/actions.js:237 -#: notebook/static/notebook/js/actions.js:238 -msgid "split cell at cursor" -msgstr "разбить ячейку при наведении курсора" - -#: notebook/static/notebook/js/actions.js:245 -#: notebook/static/notebook/js/actions.js:246 -msgid "enter edit mode" -msgstr "вход в режим редактирования" - -#: notebook/static/notebook/js/actions.js:253 -msgid "select previous cell" -msgstr "выбрать предыдущую ячейку" - -#: notebook/static/notebook/js/actions.js:254 -msgid "select cell above" -msgstr "выбрать ячейку выше" - -#: notebook/static/notebook/js/actions.js:265 -msgid "select next cell" -msgstr "выбрать следующую ячейку" - -#: notebook/static/notebook/js/actions.js:266 -msgid "select cell below" -msgstr "выбрать ячейку ниже" - -#: notebook/static/notebook/js/actions.js:277 -msgid "extend selection above" -msgstr "расширить выбор выше" - -#: notebook/static/notebook/js/actions.js:278 -msgid "extend selected cells above" -msgstr "расширить выделенные ячейки выше" - -#: notebook/static/notebook/js/actions.js:289 -msgid "extend selection below" -msgstr "расширить выбор ниже" - -#: notebook/static/notebook/js/actions.js:290 -msgid "extend selected cells below" -msgstr "расширить выделенные ячейки ниже" - -#: notebook/static/notebook/js/actions.js:301 -#: notebook/static/notebook/js/actions.js:302 -msgid "cut selected cells" -msgstr "вырезать выбранные ячейки" - -#: notebook/static/notebook/js/actions.js:312 -#: notebook/static/notebook/js/actions.js:313 -msgid "copy selected cells" -msgstr "копировать выбранные ячейки" - -#: notebook/static/notebook/js/actions.js:327 -#: notebook/static/notebook/js/actions.js:328 -msgid "paste cells above" -msgstr "вставить ячейки выше" - -#: notebook/static/notebook/js/actions.js:335 -#: notebook/static/notebook/js/actions.js:336 -msgid "paste cells below" -msgstr "вставить ячейки ниже" - -#: notebook/static/notebook/js/actions.js:344 -#: notebook/static/notebook/js/actions.js:345 -msgid "insert cell above" -msgstr "вставить ячейку выше" - -#: notebook/static/notebook/js/actions.js:354 -#: notebook/static/notebook/js/actions.js:355 -msgid "insert cell below" -msgstr "вставить ячейку ниже" - -#: notebook/static/notebook/js/actions.js:365 -#: notebook/static/notebook/js/actions.js:366 -msgid "change cell to code" -msgstr "изменить ячейку на код" - -#: notebook/static/notebook/js/actions.js:373 -#: notebook/static/notebook/js/actions.js:374 -msgid "change cell to markdown" -msgstr "изменить ячейку на markdown" - -#: notebook/static/notebook/js/actions.js:381 -#: notebook/static/notebook/js/actions.js:382 -msgid "change cell to raw" -msgstr "изменить ячейку на raw" - -#: notebook/static/notebook/js/actions.js:389 -#: notebook/static/notebook/js/actions.js:390 -msgid "change cell to heading 1" -msgstr "изменить ячейку на заголовок 1" - -#: notebook/static/notebook/js/actions.js:397 -#: notebook/static/notebook/js/actions.js:398 -msgid "change cell to heading 2" -msgstr "изменить ячейку на заголовок 2" - -#: notebook/static/notebook/js/actions.js:405 -#: notebook/static/notebook/js/actions.js:406 -msgid "change cell to heading 3" -msgstr "изменить ячейку на заголовок 3" - -#: notebook/static/notebook/js/actions.js:413 -#: notebook/static/notebook/js/actions.js:414 -msgid "change cell to heading 4" -msgstr "изменить ячейку на заголовок 4" - -#: notebook/static/notebook/js/actions.js:421 -#: notebook/static/notebook/js/actions.js:422 -msgid "change cell to heading 5" -msgstr "изменить ячейку на заголовок 5" - -#: notebook/static/notebook/js/actions.js:429 -#: notebook/static/notebook/js/actions.js:430 -msgid "change cell to heading 6" -msgstr "изменить ячейку на заголовок 6" - -#: notebook/static/notebook/js/actions.js:437 -msgid "toggle cell output" -msgstr "переключение вывода ячейки" - -#: notebook/static/notebook/js/actions.js:438 -msgid "toggle output of selected cells" -msgstr "переключить вывод выбранных ячеек" - -#: notebook/static/notebook/js/actions.js:445 -msgid "toggle cell scrolling" -msgstr "переключить прокрутку ячейки" - -#: notebook/static/notebook/js/actions.js:446 -msgid "toggle output scrolling of selected cells" -msgstr "переключить прокрутку вывода выбранных ячеек" - -#: notebook/static/notebook/js/actions.js:453 -msgid "clear cell output" -msgstr "очистить вывод ячейки" - -#: notebook/static/notebook/js/actions.js:454 -msgid "clear output of selected cells" -msgstr "очистить вывод выбранных ячеек" - -#: notebook/static/notebook/js/actions.js:460 -msgid "move cells down" -msgstr "переместить ячейки вниз" - -#: notebook/static/notebook/js/actions.js:461 -msgid "move selected cells down" -msgstr "переместить выбранные ячейки вниз" - -#: notebook/static/notebook/js/actions.js:469 -msgid "move cells up" -msgstr "переместить ячейки вверх" - -#: notebook/static/notebook/js/actions.js:470 -msgid "move selected cells up" -msgstr "переместить выбранные ячейки вверх" - -#: notebook/static/notebook/js/actions.js:478 -#: notebook/static/notebook/js/actions.js:479 -msgid "toggle line numbers" -msgstr "переключить номера строк" - -#: notebook/static/notebook/js/actions.js:486 -#: notebook/static/notebook/js/actions.js:487 -msgid "show keyboard shortcuts" -msgstr "показать сочетания клавиш клавиатуры" - -#: notebook/static/notebook/js/actions.js:494 -msgid "delete cells" -msgstr "удалить ячейки" - -#: notebook/static/notebook/js/actions.js:495 -msgid "delete selected cells" -msgstr "удалить выбранные ячейки" - -#: notebook/static/notebook/js/actions.js:502 -#: notebook/static/notebook/js/actions.js:503 -msgid "undo cell deletion" -msgstr "отменить удаление ячейки" - -#: notebook/static/notebook/js/actions.js:512 -msgid "merge cell with previous cell" -msgstr "объединить ячейку с предыдущей ячейкой" - -#: notebook/static/notebook/js/actions.js:513 -msgid "merge cell above" -msgstr "объединить ячейку выше" - -#: notebook/static/notebook/js/actions.js:519 -msgid "merge cell with next cell" -msgstr "объединить ячейку со следующей ячейкой" - -#: notebook/static/notebook/js/actions.js:520 -msgid "merge cell below" -msgstr "объединить ячейку ниже" - -#: notebook/static/notebook/js/actions.js:527 -#: notebook/static/notebook/js/actions.js:528 -msgid "merge selected cells" -msgstr "объединить выбранные ячейки" - -#: notebook/static/notebook/js/actions.js:535 -msgid "merge cells" -msgstr "объединить ячейки" - -#: notebook/static/notebook/js/actions.js:536 -msgid "" -"merge selected cells, or current cell with cell below if only one cell is " -"selected" -msgstr "" -"объединить выбранные ячейки или текущую с ячейкой ниже, если выбрана только " -"одна ячейка" - -#: notebook/static/notebook/js/actions.js:549 -msgid "show command pallette" -msgstr "показать палитру команд" - -#: notebook/static/notebook/js/actions.js:550 -msgid "open the command palette" -msgstr "открыть палитру команд" - -#: notebook/static/notebook/js/actions.js:557 -msgid "toggle all line numbers" -msgstr "переключение всех номеров строк" - -#: notebook/static/notebook/js/actions.js:558 -msgid "toggles line numbers in all cells, and persist the setting" -msgstr "переключает номера строк во всех ячейках и сохраняет настройку" - -#: notebook/static/notebook/js/actions.js:569 -msgid "show all line numbers" -msgstr "показать все номера строк" - -#: notebook/static/notebook/js/actions.js:570 -msgid "show line numbers in all cells, and persist the setting" -msgstr "показать номера строк во всех ячейках и сохранить настройку" - -#: notebook/static/notebook/js/actions.js:579 -msgid "hide all line numbers" -msgstr "скрыть все номера строк" - -#: notebook/static/notebook/js/actions.js:580 -msgid "hide line numbers in all cells, and persist the setting" -msgstr "скрыть номера строк во всех ячейках и сохранить настройки" - -# заголовок переключателя -#: notebook/static/notebook/js/actions.js:589 -msgid "toggle header" -msgstr "переключение заголовка" - -#: notebook/static/notebook/js/actions.js:590 -msgid "switch between showing and hiding the header" -msgstr "переключение между отображением и скрытием заголовка" - -#: notebook/static/notebook/js/actions.js:605 -#: notebook/static/notebook/js/actions.js:606 -msgid "show the header" -msgstr "показать заголовок" - -#: notebook/static/notebook/js/actions.js:615 -#: notebook/static/notebook/js/actions.js:616 -msgid "hide the header" -msgstr "скрыть заголовок" - -#: notebook/static/notebook/js/actions.js:646 -msgid "toggle toolbar" -msgstr "переключить панель инструментов" - -#: notebook/static/notebook/js/actions.js:647 -msgid "switch between showing and hiding the toolbar" -msgstr "переключение между отображением и скрытием панели инструментов" - -#: notebook/static/notebook/js/actions.js:660 -#: notebook/static/notebook/js/actions.js:661 -msgid "show the toolbar" -msgstr "показать панель инструментов" - -#: notebook/static/notebook/js/actions.js:669 -#: notebook/static/notebook/js/actions.js:670 -msgid "hide the toolbar" -msgstr "скрыть всплывающую подсказку" - -#: notebook/static/notebook/js/actions.js:678 -#: notebook/static/notebook/js/actions.js:679 -msgid "close the pager" -msgstr "закрыть пейджер" - -#: notebook/static/notebook/js/actions.js:704 -msgid "ignore" -msgstr "игнорировать" - -#: notebook/static/notebook/js/actions.js:710 -#: notebook/static/notebook/js/actions.js:711 -msgid "move cursor up" -msgstr "переместить курсор вверх" - -#: notebook/static/notebook/js/actions.js:731 -#: notebook/static/notebook/js/actions.js:732 -msgid "move cursor down" -msgstr "переместить курсор вниз" - -#: notebook/static/notebook/js/actions.js:750 -#: notebook/static/notebook/js/actions.js:751 -msgid "scroll notebook down" -msgstr "прокрутить блокнот вниз" - -#: notebook/static/notebook/js/actions.js:760 -#: notebook/static/notebook/js/actions.js:761 -msgid "scroll notebook up" -msgstr "прокрутить блокнот вверх" - -#: notebook/static/notebook/js/actions.js:770 -msgid "scroll cell center" -msgstr "прокрутить ячейку в центр" - -#: notebook/static/notebook/js/actions.js:771 -msgid "Scroll the current cell to the center" -msgstr "Прокрутить текущую ячейку к центру" - -#: notebook/static/notebook/js/actions.js:781 -msgid "scroll cell top" -msgstr "прокрутить ячейку вверх" - -#: notebook/static/notebook/js/actions.js:782 -msgid "Scroll the current cell to the top" -msgstr "Прокрутить текущую ячейку к верху" - -#: notebook/static/notebook/js/actions.js:792 -msgid "duplicate notebook" -msgstr "дублировать блокнот" - -#: notebook/static/notebook/js/actions.js:793 -msgid "Create and open a copy of the current notebook" -msgstr "Создать и открыть копию текущего блокнота" - -#: notebook/static/notebook/js/actions.js:799 -msgid "trust notebook" -msgstr "доверять блокноту" - -#: notebook/static/notebook/js/actions.js:800 -msgid "Trust the current notebook" -msgstr "Доверять текущему блокноту" - -#: notebook/static/notebook/js/actions.js:806 -msgid "rename notebook" -msgstr "переименовать блокнот" - -#: notebook/static/notebook/js/actions.js:807 -msgid "Rename the current notebook" -msgstr "Переименовать текущий блокнот" - -#: notebook/static/notebook/js/actions.js:813 -msgid "toggle all cells output collapsed" -msgstr "переключение сворачивания вывода всех ячеек" - -#: notebook/static/notebook/js/actions.js:814 -msgid "Toggle the hidden state of all output areas" -msgstr "Переключить скрытое состояние всех областей вывода" - -#: notebook/static/notebook/js/actions.js:820 -msgid "toggle all cells output scrolled" -msgstr "переключение прокрутки вывода всех ячеек" - -#: notebook/static/notebook/js/actions.js:821 -msgid "Toggle the scrolling state of all output areas" -msgstr "Переключить состояние прокрутки всех областей вывода" - -#: notebook/static/notebook/js/actions.js:828 -msgid "clear all cells output" -msgstr "очистить вывод всех ячеек" - -#: notebook/static/notebook/js/actions.js:829 -msgid "Clear the content of all the outputs" -msgstr "Очистить содержимое всех выводов" - -#: notebook/static/notebook/js/actions.js:835 -msgid "save notebook" -msgstr "сохранить блокнот" - -#: notebook/static/notebook/js/actions.js:836 -msgid "Save and Checkpoint" -msgstr "Сохранение и контрольная точка" - -#: notebook/static/notebook/js/cell.js:79 -msgid "Warning: accessing Cell.cm_config directly is deprecated." -msgstr "Предупреждение: прямой доступ к Cell.cm_config устарел." - -#: notebook/static/notebook/js/cell.js:763 -#, python-format -msgid "Unrecognized cell type: %s" -msgstr "Нераспознанный тип ячейки: %s" - -#: notebook/static/notebook/js/cell.js:777 -msgid "Unrecognized cell type" -msgstr "Нераспознанный тип ячейки" - -#: notebook/static/notebook/js/celltoolbar.js:296 -#, python-format -msgid "Error in cell toolbar callback %s" -msgstr "Ошибка в обратном вызове панели инструментов ячейки %s" - -#: notebook/static/notebook/js/clipboard.js:53 -#, python-format -msgid "Clipboard types: %s" -msgstr "Типы буфера обмена: %s" - -#: notebook/static/notebook/js/clipboard.js:96 -msgid "Dialog for paste from system clipboard" -msgstr "Диалоговое окно для вставки из системного буфера обмена" - -#: notebook/static/notebook/js/clipboard.js:109 -msgid "Ctrl-V" -msgstr "Ctrl-V" - -#: notebook/static/notebook/js/clipboard.js:111 -msgid "Cmd-V" -msgstr "Cmd-V" - -#: notebook/static/notebook/js/clipboard.js:113 -#, python-format -msgid "Press %s again to paste" -msgstr "Нажмите %s еще раз, чтобы вставить" - -#: notebook/static/notebook/js/clipboard.js:116 -msgid "Why is this needed? " -msgstr "Зачем это нужно? " - -#: notebook/static/notebook/js/clipboard.js:118 -msgid "We can't get paste events in this browser without a text box. " -msgstr "" -"Мы не можем получить прошлые события в этом браузере без текстового поля. " - -#: notebook/static/notebook/js/clipboard.js:119 -msgid "There's an invisible text box focused in this dialog." -msgstr "В этом диалоговом окне есть невидимое текстовое поле." - -#: notebook/static/notebook/js/clipboard.js:125 -#, python-format -msgid "%s to paste" -msgstr "%s для вставки" - -#: notebook/static/notebook/js/codecell.js:310 -msgid "Can't execute cell since kernel is not set." -msgstr "Невозможно выполнить ячейку, так как ядро не установлено." - -#: notebook/static/notebook/js/codecell.js:472 -msgid "In" -msgstr "Ввод" - -#: notebook/static/notebook/js/kernelselector.js:269 -#, python-format -msgid "Could not find a kernel matching %s. Please select a kernel:" -msgstr "Не удалось найти ядро, соответствующее %s. Пожалуйста, выберите ядро:" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Continue Without Kernel" -msgstr "Продолжить без ядра" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Set Kernel" -msgstr "Установить ядро" - -#: notebook/static/notebook/js/kernelselector.js:281 -msgid "Kernel not found" -msgstr "Ядро не найдено" - -#: notebook/static/notebook/js/kernelselector.js:319 -#: notebook/static/tree/js/newnotebook.js:99 -msgid "Creating Notebook Failed" -msgstr "Ошибка создания блокнота" - -#: notebook/static/notebook/js/kernelselector.js:320 -#: notebook/static/tree/js/notebooklist.js:1360 -#, python-format -msgid "The error was: %s" -msgstr "Ошибка в: %s" - -#: notebook/static/notebook/js/maintoolbar.js:54 -msgid "Run" -msgstr "Запуск" - -#: notebook/static/notebook/js/maintoolbar.js:76 -msgid "Code" -msgstr "Код" - -#: notebook/static/notebook/js/maintoolbar.js:77 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/static/notebook/js/maintoolbar.js:78 -msgid "Raw NBConvert" -msgstr "Необработанный NBConvert" - -#: notebook/static/notebook/js/maintoolbar.js:79 -msgid "Heading" -msgstr "Заголовок" - -#: notebook/static/notebook/js/maintoolbar.js:115 -msgid "unrecognized cell type:" -msgstr "нераспознанный тип ячейки:" - -#: notebook/static/notebook/js/mathjaxutils.js:45 -#, python-format -msgid "Failed to retrieve MathJax from '%s'" -msgstr "Не удалось получить MathJax из '%s'" - -#: notebook/static/notebook/js/mathjaxutils.js:47 -msgid "Math/LaTeX rendering will be disabled." -msgstr "Рендеринг Math/LaTeX будет отключен." - -#: notebook/static/notebook/js/menubar.js:220 -msgid "Trusted Notebook" -msgstr "Доверенный блокнот" - -#: notebook/static/notebook/js/menubar.js:226 -msgid "Trust Notebook" -msgstr "Доверять блокноту" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16 -#: notebook/static/notebook/js/menubar.js:383 -msgid "None" -msgstr "Отсутствует" - -#: notebook/static/notebook/js/menubar.js:406 -msgid "No checkpoints" -msgstr "Контрольные точки отсутствуют" - -#: notebook/static/notebook/js/menubar.js:465 -msgid "Opens in a new window" -msgstr "Откроется в новом окне" - -#: notebook/static/notebook/js/notebook.js:431 -msgid "Autosave in progress, latest changes may be lost." -msgstr "Автосохранение продолжается, последние изменения могут быть потеряны." - -#: notebook/static/notebook/js/notebook.js:433 -msgid "Unsaved changes will be lost." -msgstr "Несохраненные изменения будут потеряны." - -#: notebook/static/notebook/js/notebook.js:438 -msgid "The Kernel is busy, outputs may be lost." -msgstr "Ядро занято, вывод может быть потерян." - -#: notebook/static/notebook/js/notebook.js:461 -msgid "This notebook is version %1$s, but we only fully support up to %2$s." -msgstr "" -"Этот блокнот имеет версию %1$s, но мы полностью поддерживаем только до %2$s." - -#: notebook/static/notebook/js/notebook.js:463 -msgid "" -"You can still work with this notebook, but cell and output types introduced " -"in later notebook versions will not be available." -msgstr "" -"Вы все еще можете работать с этим блокнотом, но типы ячеек и выходных " -"данных, представленные в более поздних версиях блокнота, будут недоступны." - -#: notebook/static/notebook/js/notebook.js:470 -msgid "Restart and Run All Cells" -msgstr "Перезапуск и запуск всех ячеек" - -#: notebook/static/notebook/js/notebook.js:471 -msgid "Restart and Clear All Outputs" -msgstr "Перезапуск и очистка всего вывода" - -#: notebook/static/notebook/js/notebook.js:472 -msgid "Restart" -msgstr "Перезапуск" - -#: notebook/static/notebook/js/notebook.js:473 -msgid "Continue Running" -msgstr "Продолжить запуск" - -#: notebook/static/notebook/js/notebook.js:474 -msgid "Reload" -msgstr "Перезагрузка" - -#: notebook/static/notebook/js/notebook.js:476 -msgid "Overwrite" -msgstr "Перезапись" - -#: notebook/static/notebook/js/notebook.js:477 -msgid "Trust" -msgstr "Доверять" - -#: notebook/static/notebook/js/notebook.js:478 -msgid "Revert" -msgstr "Откат" - -#: notebook/static/notebook/js/notebook.js:483 -msgid "Newer Notebook" -msgstr "Новый Notebook" - -#: notebook/static/notebook/js/notebook.js:1548 -msgid "Use markdown headings" -msgstr "Использовать заголовки markdown" - -#: notebook/static/notebook/js/notebook.js:1550 -msgid "" -"Jupyter no longer uses special heading cells. Instead, write your headings " -"in Markdown cells using # characters:" -msgstr "" -"Jupyter больше не использует специальные ячейки заголовка. Вместо этого " -"указывайте заголовки в ячейках Markdown, используя символы #:" - -#: notebook/static/notebook/js/notebook.js:1553 -msgid "## This is a level 2 heading" -msgstr "## Это заголовок 2 уровня" - -#: notebook/static/notebook/js/notebook.js:2248 -msgid "Restart kernel and re-run the whole notebook?" -msgstr "Перезапустить ядро и перезапустить все блокноты?" - -#: notebook/static/notebook/js/notebook.js:2250 -msgid "" -"Are you sure you want to restart the current kernel and re-execute the whole " -"notebook? All variables and outputs will be lost." -msgstr "" -"Вы уверены, что хотите перезапустить текущее ядро и повторно выполнить весь " -"блокнот? Все переменные и выходные данные будут потеряны." - -#: notebook/static/notebook/js/notebook.js:2275 -msgid "Restart kernel and clear all output?" -msgstr "Перезапустить ядро и очистить весь вывод?" - -#: notebook/static/notebook/js/notebook.js:2277 -msgid "" -"Do you want to restart the current kernel and clear all output? All " -"variables and outputs will be lost." -msgstr "" -"Вы хотите перезапустить текущее ядро и очистить весь вывод? Все переменные и " -"выводы будут потеряны." - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Restart kernel?" -msgstr "Перезапустить ядро?" - -#: notebook/static/notebook/js/notebook.js:2324 -msgid "Do you want to restart the current kernel? All variables will be lost." -msgstr "Вы хотите перезапустить текущее ядро? Все переменные будут потеряны." - -#: notebook/static/notebook/js/notebook.js:2320 -msgid "Shutdown kernel?" -msgstr "Выключить ядро?" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "" -"Do you want to shutdown the current kernel? All variables will be lost." -msgstr "Вы хотите выключить текущее ядро? Все переменные будут потеряны." - -#: notebook/static/notebook/js/notebook.js:2734 -msgid "Notebook changed" -msgstr "Блокнот изменен" - -#: notebook/static/notebook/js/notebook.js:2735 -msgid "" -"The notebook file has changed on disk since the last time we opened or saved " -"it. Do you want to overwrite the file on disk with the version open here, or " -"load the version on disk (reload the page) ?" -msgstr "" -"Файл блокнота изменился на диске с момента его последнего открытия или " -"сохранения. Вы хотите перезаписать файл на диске открытой здесь версией или " -"загрузить версию с диска (перезагрузить страницу)?" - -#: notebook/static/notebook/js/notebook.js:2782 -#: notebook/static/notebook/js/notebook.js:2990 -msgid "Notebook validation failed" -msgstr "Ошибка проверки блокнота" - -#: notebook/static/notebook/js/notebook.js:2785 -msgid "" -"The save operation succeeded, but the notebook does not appear to be valid. " -"The validation error was:" -msgstr "" -"Операция сохранения прошла успешно, но блокнот, похоже, недействителен. " -"Ошибка проверки:" - -#: notebook/static/notebook/js/notebook.js:2836 -msgid "" -"A trusted Jupyter notebook may execute hidden malicious code when you open " -"it. Selecting trust will immediately reload this notebook in a trusted " -"state. For more information, see the Jupyter security documentation: " -msgstr "" -"Доверенный блокнот Jupyter может выполнять скрытый вредоносный код при " -"открытии. При выборе параметра доверие этот блокнот будет немедленно " -"перезагружен в доверенное состояние. Дополнительные сведения см. в " -"документации по безопасности Jupiter: " - -#: notebook/static/notebook/js/notebook.js:2840 -msgid "here" -msgstr "здесь" - -#: notebook/static/notebook/js/notebook.js:2848 -msgid "Trust this notebook?" -msgstr "Доверять этому блокноту?" - -#: notebook/static/notebook/js/notebook.js:2981 -msgid "Notebook failed to load" -msgstr "Ошибка загрузки блокнота" - -#: notebook/static/notebook/js/notebook.js:2983 -msgid "The error was: " -msgstr "Ошибка в: " - -#: notebook/static/notebook/js/notebook.js:2987 -msgid "See the error console for details." -msgstr "Дополнительные сведения см. в консоли ошибок." - -#: notebook/static/notebook/js/notebook.js:2995 -msgid "The notebook also failed validation:" -msgstr "Блокнот также не прошла проверку:" - -#: notebook/static/notebook/js/notebook.js:2997 -msgid "" -"An invalid notebook may not function properly. The validation error was:" -msgstr "Неисправный блокнот может работать неправильно. Ошибка проверки:" - -#: notebook/static/notebook/js/notebook.js:3036 -#, python-format -msgid "" -"This notebook has been converted from an older notebook format to the " -"current notebook format v(%s)." -msgstr "" -"Этот блокнот был преобразован из более старого формата блокнота в текущий " -"формат v(%s)." - -#: notebook/static/notebook/js/notebook.js:3038 -#, python-format -msgid "" -"This notebook has been converted from a newer notebook format to the current " -"notebook format v(%s)." -msgstr "" -"Этот блокнот был преобразован из более нового формата блокнота в текущий " -"формат v(%s)." - -#: notebook/static/notebook/js/notebook.js:3046 -msgid "" -"The next time you save this notebook, the current notebook format will be " -"used." -msgstr "" -"При следующем сохранении этого блокнота будет использоваться текущий формат " -"блокнота." - -#: notebook/static/notebook/js/notebook.js:3051 -msgid "Older versions of Jupyter may not be able to read the new format." -msgstr "" -"Старые версии Jupiter могут быть не в состоянии прочитать новый формат." - -#: notebook/static/notebook/js/notebook.js:3053 -msgid "Some features of the original notebook may not be available." -msgstr "Некоторые функции оригинального блокнота могут быть недоступны." - -#: notebook/static/notebook/js/notebook.js:3056 -msgid "To preserve the original version, close the notebook without saving it." -msgstr "Чтобы сохранить исходную версию, закройте блокнот не сохраняя его." - -#: notebook/static/notebook/js/notebook.js:3061 -msgid "Notebook converted" -msgstr "Блокнот преобразован" - -#: notebook/static/notebook/js/notebook.js:3083 -msgid "(No name)" -msgstr "(Без имени)" - -#: notebook/static/notebook/js/notebook.js:3131 -#, python-format -msgid "" -"An unknown error occurred while loading this notebook. This version can load " -"notebook formats %s or earlier. See the server log for details." -msgstr "" -"При загрузке этого блокнота произошла неизвестная ошибка. Эта версия может " -"загружать форматы блокнотов %s или более ранние. Дополнительные сведения см. " -"в журнале сервера." - -#: notebook/static/notebook/js/notebook.js:3142 -msgid "Error loading notebook" -msgstr "Ошибка загрузки блокнота" - -#: notebook/static/notebook/js/notebook.js:3243 -msgid "Are you sure you want to revert the notebook to the latest checkpoint?" -msgstr "Вы уверены, что хотите вернуть блокнот к последней контрольной точке?" - -#: notebook/static/notebook/js/notebook.js:3246 -msgid "This cannot be undone." -msgstr "Этого уже не исправить." - -#: notebook/static/notebook/js/notebook.js:3249 -msgid "The checkpoint was last updated at:" -msgstr "Последний раз контрольная точка обновлялась:" - -#: notebook/static/notebook/js/notebook.js:3260 -msgid "Revert notebook to checkpoint" -msgstr "Откатить блокнот до контрольной точки" - -#: notebook/static/notebook/js/notificationarea.js:77 -#: notebook/static/notebook/js/tour.js:61 -#: notebook/static/notebook/js/tour.js:67 -msgid "Edit Mode" -msgstr "Режим редактирования" - -#: notebook/static/notebook/js/notificationarea.js:84 -#: notebook/static/notebook/js/notificationarea.js:88 -#: notebook/static/notebook/js/tour.js:54 -msgid "Command Mode" -msgstr "Командный режим" - -#: notebook/static/notebook/js/notificationarea.js:95 -msgid "Kernel Created" -msgstr "Ядро создано" - -#: notebook/static/notebook/js/notificationarea.js:99 -msgid "Connecting to kernel" -msgstr "Подключение к ядру" - -#: notebook/static/notebook/js/notificationarea.js:103 -msgid "Not Connected" -msgstr "Не подключено" - -#: notebook/static/notebook/js/notificationarea.js:106 -msgid "click to reconnect" -msgstr "нажмите для переподключения" - -#: notebook/static/notebook/js/notificationarea.js:115 -msgid "Restarting kernel" -msgstr "Перезапуск ядра" - -#: notebook/static/notebook/js/notificationarea.js:129 -msgid "Kernel Restarting" -msgstr "Перезапуск ядра" - -#: notebook/static/notebook/js/notificationarea.js:130 -msgid "The kernel appears to have died. It will restart automatically." -msgstr "Ядро, по-видимому, умерло. Оно будет перезапущено автоматически." - -#: notebook/static/notebook/js/notificationarea.js:140 -#: notebook/static/notebook/js/notificationarea.js:198 -#: notebook/static/notebook/js/notificationarea.js:218 -msgid "Dead kernel" -msgstr "Убить ядро" - -#: notebook/static/notebook/js/notificationarea.js:141 -#: notebook/static/notebook/js/notificationarea.js:219 -#: notebook/static/notebook/js/notificationarea.js:266 -msgid "Kernel Dead" -msgstr "Ядро мертво" - -#: notebook/static/notebook/js/notificationarea.js:145 -msgid "Interrupting kernel" -msgstr "Прерывание ядра" - -#: notebook/static/notebook/js/notificationarea.js:151 -msgid "No Connection to Kernel" -msgstr "Нет связи с ядром" - -#: notebook/static/notebook/js/notificationarea.js:161 -msgid "" -"A connection to the notebook server could not be established. The notebook " -"will continue trying to reconnect. Check your network connection or notebook " -"server configuration." -msgstr "" -"Не удалось установить соединение с сервером блокнота. Блокнот будет " -"продолжать попытки повторного подключения. Проверьте сетевое подключение или " -"конфигурацию сервера блокнота." - -#: notebook/static/notebook/js/notificationarea.js:166 -msgid "Connection failed" -msgstr "Ошибка подключения" - -#: notebook/static/notebook/js/notificationarea.js:179 -msgid "No kernel" -msgstr "Ядро отсутствует" - -#: notebook/static/notebook/js/notificationarea.js:180 -msgid "Kernel is not running" -msgstr "Ядро не запущено" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Don't Restart" -msgstr "Не перезагружать" - -#: notebook/static/notebook/js/notificationarea.js:187 -msgid "Try Restarting Now" -msgstr "Попробуйте перезагрузить сейчас" - -#: notebook/static/notebook/js/notificationarea.js:191 -msgid "" -"The kernel has died, and the automatic restart has failed. It is possible " -"the kernel cannot be restarted. If you are not able to restart the kernel, " -"you will still be able to save the notebook, but running code will no longer " -"work until the notebook is reopened." -msgstr "" -"Ядро умерло и автоматический перезапуск не удался. Вполне возможно, что ядро " -"не может быть перезапущено. Если вам не удастся перезапустить ядро - вы все " -"равно сможете сохранить блокнот, но запущенный код больше не будет работать " -"до тех пор, пока блокнот не будет снова открыт." - -#: notebook/static/notebook/js/notificationarea.js:225 -msgid "No Kernel" -msgstr "Ядро отсутствует" - -#: notebook/static/notebook/js/notificationarea.js:252 -msgid "Failed to start the kernel" -msgstr "Не удалось запустить ядро" - -#: notebook/static/notebook/js/notificationarea.js:272 -#: notebook/static/notebook/js/notificationarea.js:292 -#: notebook/static/notebook/js/notificationarea.js:306 -msgid "Kernel Busy" -msgstr "Ядро занято" - -#: notebook/static/notebook/js/notificationarea.js:273 -msgid "Kernel starting, please wait..." -msgstr "Перезапуск ядра, пожалуйста подождите..." - -#: notebook/static/notebook/js/notificationarea.js:279 -#: notebook/static/notebook/js/notificationarea.js:286 -msgid "Kernel Idle" -msgstr "Ядро бездействует" - -#: notebook/static/notebook/js/notificationarea.js:280 -msgid "Kernel ready" -msgstr "Ядро готово" - -#: notebook/static/notebook/js/notificationarea.js:297 -msgid "Using kernel: " -msgstr "Использование ядра: " - -#: notebook/static/notebook/js/notificationarea.js:298 -msgid "Only candidate for language: %1$s was %2$s." -msgstr "Единственный кандидат на язык: %1$s был %2$s." - -#: notebook/static/notebook/js/notificationarea.js:319 -msgid "Loading notebook" -msgstr "Загрузка блокнота" - -#: notebook/static/notebook/js/notificationarea.js:322 -msgid "Notebook loaded" -msgstr "Блокнот загружен" - -#: notebook/static/notebook/js/notificationarea.js:325 -msgid "Saving notebook" -msgstr "Сохранение блокнота" - -#: notebook/static/notebook/js/notificationarea.js:328 -msgid "Notebook saved" -msgstr "Блокнот сохранен" - -#: notebook/static/notebook/js/notificationarea.js:331 -msgid "Notebook save failed" -msgstr "Ошибка сохранения блокнота" - -#: notebook/static/notebook/js/notificationarea.js:334 -msgid "Notebook copy failed" -msgstr "Ошибка копирования блокнота" - -#: notebook/static/notebook/js/notificationarea.js:339 -msgid "Checkpoint created" -msgstr "Контрольная точка создана" - -#: notebook/static/notebook/js/notificationarea.js:347 -msgid "Checkpoint failed" -msgstr "Ошибка контрольной точки" - -#: notebook/static/notebook/js/notificationarea.js:350 -msgid "Checkpoint deleted" -msgstr "Контрольная точка удалена" - -#: notebook/static/notebook/js/notificationarea.js:353 -msgid "Checkpoint delete failed" -msgstr "Ошибка удаления контрольной точки" - -#: notebook/static/notebook/js/notificationarea.js:356 -msgid "Restoring to checkpoint..." -msgstr "Восстановление до контрольной точки..." - -#: notebook/static/notebook/js/notificationarea.js:359 -msgid "Checkpoint restore failed" -msgstr "Не удалось восстановить контрольную точку" - -#: notebook/static/notebook/js/notificationarea.js:364 -msgid "Autosave disabled" -msgstr "Автосохранение отключено" - -#: notebook/static/notebook/js/notificationarea.js:367 -#, python-format -msgid "Saving every %d sec." -msgstr "Сохранение каждые %d секунд." - -#: notebook/static/notebook/js/notificationarea.js:383 -msgid "Trusted" -msgstr "Доверенный" - -#: notebook/static/notebook/js/notificationarea.js:385 -msgid "Not Trusted" -msgstr "Не доверять" - -#: notebook/static/notebook/js/outputarea.js:75 -msgid "click to expand output" -msgstr "щелкните чтобы развернуть вывод" - -#: notebook/static/notebook/js/outputarea.js:79 -msgid "click to expand output; double click to hide output" -msgstr "щелкните чтобы развернуть вывод; двойной щелчок чтобы скрыть вывод" - -#: notebook/static/notebook/js/outputarea.js:167 -msgid "click to unscroll output; double click to hide" -msgstr "щелчок для прокрутки вывода; двойной щелчок - чтобы скрыть" - -#: notebook/static/notebook/js/outputarea.js:174 -msgid "click to scroll output; double click to hide" -msgstr "щелчок для прокрутки вывода; двойной щелчок - чтобы скрыть" - -#: notebook/static/notebook/js/outputarea.js:422 -msgid "Javascript error adding output!" -msgstr "Ошибка Javascript при добавлении вывода!" - -#: notebook/static/notebook/js/outputarea.js:427 -msgid "See your browser Javascript console for more details." -msgstr "" -"Дополнительные сведения см. в разделе консоль Javascript вашего браузера." - -#: notebook/static/notebook/js/outputarea.js:468 -#, python-format -msgid "Out[%d]:" -msgstr "Вывод[%d]:" - -#: notebook/static/notebook/js/outputarea.js:577 -#, python-format -msgid "Unrecognized output: %s" -msgstr "Нераспознанный вывод: %s" - -#: notebook/static/notebook/js/pager.js:36 -msgid "Open the pager in an external window" -msgstr "Открыть пейджер во внешнем окне" - -#: notebook/static/notebook/js/pager.js:45 -msgid "Close the pager" -msgstr "Закрыть пейджер" - -#: notebook/static/notebook/js/pager.js:148 -msgid "Jupyter Pager" -msgstr "Пейджер Jupyter" - -#: notebook/static/notebook/js/quickhelp.js:39 -#: notebook/static/notebook/js/quickhelp.js:49 -#: notebook/static/notebook/js/quickhelp.js:50 -msgid "go to cell start" -msgstr "перейти к началу ячейки" - -#: notebook/static/notebook/js/quickhelp.js:40 -#: notebook/static/notebook/js/quickhelp.js:51 -#: notebook/static/notebook/js/quickhelp.js:52 -msgid "go to cell end" -msgstr "перейти к концу ячейки" - -#: notebook/static/notebook/js/quickhelp.js:41 -#: notebook/static/notebook/js/quickhelp.js:53 -msgid "go one word left" -msgstr "перейти на слово влево" - -#: notebook/static/notebook/js/quickhelp.js:42 -#: notebook/static/notebook/js/quickhelp.js:54 -msgid "go one word right" -msgstr "перейти на слово вправо" - -#: notebook/static/notebook/js/quickhelp.js:43 -#: notebook/static/notebook/js/quickhelp.js:55 -msgid "delete word before" -msgstr "удалить слово перед" - -#: notebook/static/notebook/js/quickhelp.js:44 -#: notebook/static/notebook/js/quickhelp.js:56 -msgid "delete word after" -msgstr "удалить слово после" - -#: notebook/static/notebook/js/quickhelp.js:61 -msgid "code completion or indent" -msgstr "завершение кода или отступ" - -#: notebook/static/notebook/js/quickhelp.js:62 -msgid "tooltip" -msgstr "всплывающая подсказка" - -#: notebook/static/notebook/js/quickhelp.js:63 -msgid "indent" -msgstr "отступ" - -#: notebook/static/notebook/js/quickhelp.js:64 -msgid "dedent" -msgstr "dedent" - -#: notebook/static/notebook/js/quickhelp.js:65 -msgid "select all" -msgstr "выбрать всё" - -#: notebook/static/notebook/js/quickhelp.js:66 -msgid "undo" -msgstr "отменить" - -#: notebook/static/notebook/js/quickhelp.js:67 -#: notebook/static/notebook/js/quickhelp.js:68 -msgid "redo" -msgstr "повторить" - -#: notebook/static/notebook/js/quickhelp.js:102 -#: notebook/static/notebook/js/quickhelp.js:243 -msgid "Shift" -msgstr "Shift" - -#: notebook/static/notebook/js/quickhelp.js:103 -msgid "Alt" -msgstr "Alt" - -#: notebook/static/notebook/js/quickhelp.js:104 -msgid "Up" -msgstr "Вверх" - -#: notebook/static/notebook/js/quickhelp.js:105 -msgid "Down" -msgstr "Вниз" - -#: notebook/static/notebook/js/quickhelp.js:106 -msgid "Left" -msgstr "Лево" - -#: notebook/static/notebook/js/quickhelp.js:107 -msgid "Right" -msgstr "Право" - -#: notebook/static/notebook/js/quickhelp.js:108 -#: notebook/static/notebook/js/quickhelp.js:246 -msgid "Tab" -msgstr "Tab" - -#: notebook/static/notebook/js/quickhelp.js:109 -msgid "Caps Lock" -msgstr "CapsLock" - -#: notebook/static/notebook/js/quickhelp.js:110 -#: notebook/static/notebook/js/quickhelp.js:269 -msgid "Esc" -msgstr "Esc" - -#: notebook/static/notebook/js/quickhelp.js:111 -msgid "Ctrl" -msgstr "Ctrl" - -#: notebook/static/notebook/js/quickhelp.js:112 -#: notebook/static/notebook/js/quickhelp.js:290 -msgid "Enter" -msgstr "Enter" - -#: notebook/static/notebook/js/quickhelp.js:113 -msgid "Page Up" -msgstr "Страница вверх" - -#: notebook/static/notebook/js/quickhelp.js:114 -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "Page Down" -msgstr "Страница вниз" - -#: notebook/static/notebook/js/quickhelp.js:115 -msgid "Home" -msgstr "Домой" - -#: notebook/static/notebook/js/quickhelp.js:116 -msgid "End" -msgstr "Конец" - -#: notebook/static/notebook/js/quickhelp.js:117 -#: notebook/static/notebook/js/quickhelp.js:245 -msgid "Space" -msgstr "Пробел" - -#: notebook/static/notebook/js/quickhelp.js:118 -msgid "Backspace" -msgstr "Бэкспейс" - -#: notebook/static/notebook/js/quickhelp.js:119 -msgid "Minus" -msgstr "Минус" - -#: notebook/static/notebook/js/quickhelp.js:130 -msgid "PageUp" -msgstr "СтраницаВверх" - -#: notebook/static/notebook/js/quickhelp.js:197 -msgid "The Jupyter Notebook has two different keyboard input modes." -msgstr "Jupyter Notebook имеет два различных режима ввода с клавиатуры." - -#: notebook/static/notebook/js/quickhelp.js:199 -msgid "" -"Edit mode allows you to type code or text into a cell and is " -"indicated by a green cell border." -msgstr "" -"Режим редактирования позволяет вводить код или текст в ячейку и " -"обозначается зеленой рамкой ячейки." - -#: notebook/static/notebook/js/quickhelp.js:201 -msgid "" -"Command mode binds the keyboard to notebook level commands and is " -"indicated by a grey cell border with a blue left margin." -msgstr "" -"Командный режим связывает клавиатуру с командами уровня блокнота и " -"обозначается серой рамкой ячейки с синим левым краем." - -#: notebook/static/notebook/js/quickhelp.js:222 -#: notebook/static/notebook/js/tooltip.js:58 -#: notebook/static/notebook/js/tooltip.js:69 -msgid "Close" -msgstr "Закрыть" - -#: notebook/static/notebook/js/quickhelp.js:225 -msgid "Keyboard shortcuts" -msgstr "Сочетания клавиш" - -#: notebook/static/notebook/js/quickhelp.js:240 -msgid "Command" -msgstr "Команда" - -#: notebook/static/notebook/js/quickhelp.js:241 -msgid "Control" -msgstr "Управление" - -#: notebook/static/notebook/js/quickhelp.js:242 -msgid "Option" -msgstr "Параметр" - -#: notebook/static/notebook/js/quickhelp.js:244 -msgid "Return" -msgstr "Возврат" - -#: notebook/static/notebook/js/quickhelp.js:270 -#, python-format -msgid "Command Mode (press %s to enable)" -msgstr "Командный режим (нажмите %s для включения)" - -#: notebook/static/notebook/js/quickhelp.js:272 -msgid "Edit Shortcuts" -msgstr "Редактировать ярлыки" - -#: notebook/static/notebook/js/quickhelp.js:275 -msgid "edit command-mode keyboard shortcuts" -msgstr "редактировать сочетания клавиш командного-режима" - -#: notebook/static/notebook/js/quickhelp.js:292 -#, python-format -msgid "Edit Mode (press %s to enable)" -msgstr "Режим редактирования (нажмите %s для включения)" - -#: notebook/static/notebook/js/savewidget.js:49 -msgid "Autosave Failed!" -msgstr "Автосохранение не удалось!" - -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:846 -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Rename" -msgstr "Переименование" - -#: notebook/static/notebook/js/savewidget.js:78 -#: notebook/static/tree/js/notebooklist.js:837 -msgid "Enter a new notebook name:" -msgstr "Введите новое имя блокнота:" - -#: notebook/static/notebook/js/savewidget.js:86 -msgid "Rename Notebook" -msgstr "Переименовать блокнот" - -#: notebook/static/notebook/js/savewidget.js:98 -msgid "" -"Invalid notebook name. Notebook names must have 1 or more characters and can " -"contain any characters except :/\\. Please enter a new notebook name:" -msgstr "" -"Недействительное имя блокнота. Имена блокнотов должны иметь 1 или более " -"символов и могут содержать любые символы, кроме :/\\. Пожалуйста, введите " -"новое имя блокнота:" - -#: notebook/static/notebook/js/savewidget.js:103 -msgid "Renaming..." -msgstr "Переименование..." - -#: notebook/static/notebook/js/savewidget.js:109 -msgid "Unknown error" -msgstr "Неизвестная ошибка" - -#: notebook/static/notebook/js/savewidget.js:178 -msgid "no checkpoint" -msgstr "контрольная точка отсутствует" - -#: notebook/static/notebook/js/savewidget.js:193 -#, python-format -msgid "Last Checkpoint: %s" -msgstr "Последняя контрольная точка: %s" - -#: notebook/static/notebook/js/savewidget.js:217 -msgid "(unsaved changes)" -msgstr "(несохраненные изменения)" - -#: notebook/static/notebook/js/savewidget.js:219 -msgid "(autosaved)" -msgstr "(автосохранение)" - -#: notebook/static/notebook/js/searchandreplace.js:74 -#, python-format -msgid "" -"Warning: too many matches (%d). Some changes might not be shown or applied." -msgstr "" -"Предупреждение: слишком много совпадений (%d). Некоторые изменения могут " -"быть не показаны или не применены." - -#: notebook/static/notebook/js/searchandreplace.js:77 -#, python-format -msgid "%d match" -msgid_plural "%d matches" -msgstr[0] "%d совпадение" -msgstr[1] "%d совпадения" -msgstr[2] "%d совпадений" - -#: notebook/static/notebook/js/searchandreplace.js:145 -msgid "More than 100 matches, aborting" -msgstr "Более 100 совпадений, прерывание" - -#: notebook/static/notebook/js/searchandreplace.js:166 -msgid "Use regex (JavaScript regex syntax)" -msgstr "" -"Используйте регулярное выражение (синтаксис регулярных выражений JavaScript)" - -#: notebook/static/notebook/js/searchandreplace.js:174 -msgid "Replace in selected cells" -msgstr "Заменить в выбранных ячейках" - -#: notebook/static/notebook/js/searchandreplace.js:181 -msgid "Match case" -msgstr "Учитывать регистр" - -#: notebook/static/notebook/js/searchandreplace.js:187 -msgid "Find" -msgstr "Поиск" - -#: notebook/static/notebook/js/searchandreplace.js:203 -msgid "Replace" -msgstr "Замена" - -#: notebook/static/notebook/js/searchandreplace.js:255 -msgid "No matches, invalid or empty regular expression" -msgstr "Нет совпадений, недопустимое или пустое регулярное выражение" - -#: notebook/static/notebook/js/searchandreplace.js:370 -msgid "Replace All" -msgstr "Заменить всё" - -#: notebook/static/notebook/js/searchandreplace.js:374 -msgid "Find and Replace" -msgstr "Поиск и замена" - -#: notebook/static/notebook/js/searchandreplace.js:400 -#: notebook/static/notebook/js/searchandreplace.js:401 -msgid "find and replace" -msgstr "поиск и замена" - -#: notebook/static/notebook/js/textcell.js:551 -msgid "" -"Write raw LaTeX or other formats here, for use with nbconvert. It will not " -"be rendered in the notebook. When passing through nbconvert, a Raw Cell's " -"content is added to the output unmodified." -msgstr "" -"Пишите сюда необработанный LaTeX или другие форматы для использования с " -"nbconvert. Он не будет отображаться в блокноте. При прохождении через " -"nbconvert содержимое необработанных ячеек добавляется к выводу неизмененным." - -#: notebook/static/notebook/js/tooltip.js:41 -msgid "Grow the tooltip vertically (press shift-tab twice)" -msgstr "Растяните всплывающую подсказку вертикально (нажмите shift-tab дважды)" - -#: notebook/static/notebook/js/tooltip.js:48 -msgid "show the current docstring in pager (press shift-tab 4 times)" -msgstr "" -"показать текущую строку документа в пейджере (нажмите shift-tab 4 раза)" - -#: notebook/static/notebook/js/tooltip.js:49 -msgid "Open in Pager" -msgstr "Открыть в пейджере" - -#: notebook/static/notebook/js/tooltip.js:68 -msgid "Tooltip will linger for 10 seconds while you type" -msgstr "" -"Всплывающая подсказка будет задерживаться в течение 10 секунд, пока вы " -"набираете текст" - -#: notebook/static/notebook/js/tour.js:27 -msgid "Welcome to the Notebook Tour" -msgstr "Добро пожаловать в тур по Notebook" - -#: notebook/static/notebook/js/tour.js:30 -msgid "You can use the left and right arrow keys to go backwards and forwards." -msgstr "" -"Вы можете использовать клавиши со стрелками влево и вправо чтобы двигаться " -"назад и вперед." - -#: notebook/static/notebook/js/tour.js:33 -msgid "Filename" -msgstr "Имя файла" - -#: notebook/static/notebook/js/tour.js:35 -msgid "Click here to change the filename for this notebook." -msgstr "Нажмите здесь чтобы изменить имя файла для этого блокнота." - -#: notebook/static/notebook/js/tour.js:39 -msgid "Notebook Menubar" -msgstr "Строка меню блокнота" - -#: notebook/static/notebook/js/tour.js:40 -msgid "" -"The menubar has menus for actions on the notebook, its cells, and the kernel " -"it communicates with." -msgstr "" -"Панель меню имеет меню для действий с блокнотом, ее ячейками и ядром, с " -"которым она взаимодействует." - -#: notebook/static/notebook/js/tour.js:44 -msgid "Notebook Toolbar" -msgstr "Панель инструментов блокнота" - -#: notebook/static/notebook/js/tour.js:45 -msgid "" -"The toolbar has buttons for the most common actions. Hover your mouse over " -"each button for more information." -msgstr "" -"На панели инструментов есть кнопки для наиболее распространенных действий. " -"Наведите курсор мыши на каждую кнопку для получения дополнительной " -"информации." - -#: notebook/static/notebook/js/tour.js:48 -msgid "Mode Indicator" -msgstr "Индикатор режима" - -#: notebook/static/notebook/js/tour.js:50 -msgid "" -"The Notebook has two modes: Edit Mode and Command Mode. In this area, an " -"indicator can appear to tell you which mode you are in." -msgstr "" -"Notebook имеет два режима работы: режим редактирования и командный режим. В " -"этой области может появиться индикатор, сообщающий вам, в каком режиме вы " -"находитесь." - -#: notebook/static/notebook/js/tour.js:58 -msgid "" -"Right now you are in Command Mode, and many keyboard shortcuts are " -"available. In this mode, no icon is displayed in the indicator area." -msgstr "" -"Прямо сейчас вы находитесь в командном режиме и многие сочетания клавиш " -"доступны. В этом режиме значок в области индикатора не отображается." - -#: notebook/static/notebook/js/tour.js:64 -msgid "" -"Pressing Enter or clicking in the input text area of the cell " -"switches to Edit Mode." -msgstr "" -"Нажатие кнопки Enter или щелчок в области ввода текста ячейки " -"переключает ее в режим редактирования." - -#: notebook/static/notebook/js/tour.js:70 -msgid "" -"Notice that the border around the currently active cell changed color. " -"Typing will insert text into the currently active cell." -msgstr "" -"Обратите внимание, что граница вокруг текущей активной ячейки изменила цвет. " -"Ввод приведет к вставке текста в текущую активную ячейку." - -#: notebook/static/notebook/js/tour.js:73 -msgid "Back to Command Mode" -msgstr "Возврат к командному режиму" - -#: notebook/static/notebook/js/tour.js:76 -msgid "" -"Pressing Esc or clicking outside of the input text area takes " -"you back to Command Mode." -msgstr "" -"Нажатие кнопки Esc или щелчок за пределами области ввода текста " -"возвращает вас в командный режим." - -#: notebook/static/notebook/js/tour.js:79 -msgid "Keyboard Shortcuts" -msgstr "Сочетания клавиш" - -#: notebook/static/notebook/js/tour.js:91 -msgid "You can click here to get a list of all of the keyboard shortcuts." -msgstr "Вы можете нажать здесь, чтобы получить список всех сочетаний клавиш." - -#: notebook/static/notebook/js/tour.js:94 -#: notebook/static/notebook/js/tour.js:100 -msgid "Kernel Indicator" -msgstr "Индикатор ядра" - -#: notebook/static/notebook/js/tour.js:97 -msgid "" -"This is the Kernel indicator. It looks like this when the Kernel is idle." -msgstr "Это и есть индикатор ядра. Он выглядит так, когда ядро простаивает." - -#: notebook/static/notebook/js/tour.js:103 -msgid "The Kernel indicator looks like this when the Kernel is busy." -msgstr "Индикатор ядра выглядит так, когда ядро занято." - -#: notebook/static/notebook/js/tour.js:107 -msgid "Interrupting the Kernel" -msgstr "Прерывание ядра" - -#: notebook/static/notebook/js/tour.js:109 -msgid "To cancel a computation in progress, you can click here." -msgstr "Чтобы отменить выполняемые вычисления - вы можете нажать здесь." - -#: notebook/static/notebook/js/tour.js:114 -msgid "Notification Area" -msgstr "Область уведомлений" - -#: notebook/static/notebook/js/tour.js:115 -msgid "" -"Messages in response to user actions (Save, Interrupt, etc.) appear here." -msgstr "" -"Сообщения в ответ на действия пользователя (сохранение, прерывание и т. д.) " -"появятся здесь." - -#: notebook/static/notebook/js/tour.js:117 -msgid "End of Tour" -msgstr "Конец обзора" - -#: notebook/static/notebook/js/tour.js:120 -msgid "This concludes the Jupyter Notebook User Interface Tour." -msgstr "" -"На этом завершается экскурсия по пользовательскому интерфейсу Jupyter " -"Notebook." - -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32 -msgid "Edit Attachments" -msgstr "Редактировать вложения" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:19 -msgid "Cell" -msgstr "Ячейка" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:29 -#: notebook/static/notebook/js/celltoolbarpresets/default.js:47 -msgid "Edit Metadata" -msgstr "Редактировать метаданные" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22 -msgid "Custom" -msgstr "Пользовательский" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32 -msgid "Set the MIME type of the raw cell:" -msgstr "Установите тип MIME необработанной ячейки:" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40 -msgid "Raw Cell MIME Type" -msgstr "Необработанный MIME-тип ячейки" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74 -msgid "Raw NBConvert Format" -msgstr "Необработанный формат NBConvert" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81 -msgid "Raw Cell Format" -msgstr "Необработанный формат ячейки" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15 -msgid "Slide" -msgstr "Слайд" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:16 -msgid "Sub-Slide" -msgstr "Под-слайд" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:17 -msgid "Fragment" -msgstr "Фрагмент" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:18 -msgid "Skip" -msgstr "Пропустить" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:19 -msgid "Notes" -msgstr "Примечания" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35 -msgid "Slide Type" -msgstr "Тип слайда" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41 -msgid "Slideshow" -msgstr "Слайд-шоу" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:133 -msgid "Add tag" -msgstr "Добавить тег" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163 -msgid "" -"Edit the list of tags below. All whitespace is treated as tag separators." -msgstr "" -"Отредактируйте список тегов ниже. Все пробелы рассматриваются как " -"разделители тегов." - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172 -msgid "Edit the tags" -msgstr "Редактировать теги" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186 -msgid "Edit Tags" -msgstr "Редактировать теги" - -#: notebook/static/tree/js/kernellist.js:86 -#: notebook/static/tree/js/terminallist.js:105 -msgid "Shutdown" -msgstr "Выключение" - -#: notebook/static/tree/js/newnotebook.js:70 -#, python-format -msgid "Create a new notebook with %s" -msgstr "Создать новый блокнот с %s" - -#: notebook/static/tree/js/newnotebook.js:101 -msgid "An error occurred while creating a new notebook." -msgstr "При создании нового блокнота произошла ошибка." - -#: notebook/static/tree/js/notebooklist.js:122 -msgid "Creating File Failed" -msgstr "Ошибка создания файла" - -#: notebook/static/tree/js/notebooklist.js:124 -msgid "An error occurred while creating a new file." -msgstr "При создании нового файла произошла ошибка." - -#: notebook/static/tree/js/notebooklist.js:142 -msgid "Creating Folder Failed" -msgstr "Ошибка создания папки" - -#: notebook/static/tree/js/notebooklist.js:144 -msgid "An error occurred while creating a new folder." -msgstr "При создании новой папки произошла ошибка." - -#: notebook/static/tree/js/notebooklist.js:271 -msgid "Failed to read file" -msgstr "Ошибка чтения файла" - -#: notebook/static/tree/js/notebooklist.js:272 -#, python-format -msgid "Failed to read file %s" -msgstr "Ошибка чтения файла %s" - -#: notebook/static/tree/js/notebooklist.js:283 -#, python-format -msgid "The file size is %d MB. Do you still want to upload it?" -msgstr "Размер файла - %d MB. Вы все еще хотите загрузить его?" - -#: notebook/static/tree/js/notebooklist.js:286 -msgid "Large file size warning" -msgstr "Предупреждение о большом размере файла" - -#: notebook/static/tree/js/notebooklist.js:355 -msgid "Server error: " -msgstr "Ошибка сервера: " - -#: notebook/static/tree/js/notebooklist.js:390 -msgid "The notebook list is empty." -msgstr "Список блокнотов пуст." - -#: notebook/static/tree/js/notebooklist.js:463 -msgid "Click here to rename, delete, etc." -msgstr "Нажмите здесь, чтобы переименовать, удалить и т.д." - -#: notebook/static/tree/js/notebooklist.js:503 -msgid "Running" -msgstr "Запустить" - -#: notebook/static/tree/js/notebooklist.js:835 -msgid "Enter a new file name:" -msgstr "Введите новое имя файла:" - -#: notebook/static/tree/js/notebooklist.js:836 -msgid "Enter a new directory name:" -msgstr "Введите новое название каталога:" - -#: notebook/static/tree/js/notebooklist.js:838 -msgid "Enter a new name:" -msgstr "Введите новое имя:" - -#: notebook/static/tree/js/notebooklist.js:843 -msgid "Rename file" -msgstr "Переименовать файл" - -#: notebook/static/tree/js/notebooklist.js:844 -msgid "Rename directory" -msgstr "Переименовать директорию" - -#: notebook/static/tree/js/notebooklist.js:845 -msgid "Rename notebook" -msgstr "Переименовать блокнот" - -#: notebook/static/tree/js/notebooklist.js:859 -msgid "Move" -msgstr "Перемещение" - -#: notebook/static/tree/js/notebooklist.js:875 -msgid "An error occurred while renaming \"%1$s\" to \"%2$s\"." -msgstr "Произошла ошибка при переименовании \"%1$s\" в \"%2$s\"." - -#: notebook/static/tree/js/notebooklist.js:878 -msgid "Rename Failed" -msgstr "Ошибка переименования" - -#: notebook/static/tree/js/notebooklist.js:927 -#, python-format -msgid "Enter a new destination directory path for this item:" -msgid_plural "Enter a new destination directory path for these %d items:" -msgstr[0] "Введите новый путь к каталогу назначения для этого %d элемента:" -msgstr[1] "Введите новый путь к каталогу назначения для этих %d элементов:" -msgstr[2] "Введите новый путь к каталогу назначения для этих %d элементов:" - -#: notebook/static/tree/js/notebooklist.js:940 -#, python-format -msgid "Move an Item" -msgid_plural "Move %d Items" -msgstr[0] "Переместить %d элемент" -msgstr[1] "Переместить %d элемента" -msgstr[2] "Переместить %d элементов" - -#: notebook/static/tree/js/notebooklist.js:959 -msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"." -msgstr "Произошла ошибка при перемещении \"%1$s\" из \"%2$s\" в \"%3$s\"." - -#: notebook/static/tree/js/notebooklist.js:961 -msgid "Move Failed" -msgstr "Ошибка перемещения" - -#: notebook/static/tree/js/notebooklist.js:1007 -#, python-format -msgid "Are you sure you want to permanently delete: \"%s\"?" -msgid_plural "" -"Are you sure you want to permanently delete the %d files or folders selected?" -msgstr[0] "" -"Вы уверены, что хотите навсегда удалить файл или папку \"%s\"?" -msgstr[1] "" -"Вы уверены, что хотите навсегда удалить %d выбранных файла или папки?" -msgstr[2] "" -"Вы уверены, что хотите навсегда удалить %d выбранных файлов или папок?" - -#: notebook/static/tree/js/notebooklist.js:1035 -#, python-format -msgid "An error occurred while deleting \"%s\"." -msgstr "Произошла ошибка при удалении \"%s\"." - -#: notebook/static/tree/js/notebooklist.js:1037 -msgid "Delete Failed" -msgstr "Ошибка удаления" - -#: notebook/static/tree/js/notebooklist.js:1078 -#, python-format -msgid "Are you sure you want to duplicate: \"%s\"?" -msgid_plural "Are you sure you want to duplicate the %d files selected?" -msgstr[0] "Вы уверены, что хотите скопировать файл \"%s\"?" -msgstr[1] "Вы уверены, что хотите скопировать %d выбранных файла?" -msgstr[2] "Вы уверены, что хотите скопировать %d выбранных файлов?" - -#: notebook/static/tree/js/notebooklist.js:1088 -msgid "Duplicate" -msgstr "Скопировать" - -#: notebook/static/tree/js/notebooklist.js:1102 -#, python-format -msgid "An error occurred while duplicating \"%s\"." -msgstr "Произошла ошибка при копировании \"%s\"." - -#: notebook/static/tree/js/notebooklist.js:1104 -msgid "Duplicate Failed" -msgstr "Ошибка дублирования" - -#: notebook/static/tree/js/notebooklist.js:1323 -msgid "Upload" -msgstr "Загрузить" - -#: notebook/static/tree/js/notebooklist.js:1332 -msgid "Invalid file name" -msgstr "Неверное имя файла" - -#: notebook/static/tree/js/notebooklist.js:1333 -msgid "File names must be at least one character and not start with a period" -msgstr "" -"Имена файлов должны состоять как минимум из одного символа и не начинаться с " -"точки" - -#: notebook/static/tree/js/notebooklist.js:1362 -msgid "Cannot upload invalid Notebook" -msgstr "Невозможно загрузить недействительный Notebook" - -#: notebook/static/tree/js/notebooklist.js:1395 -#, python-format -msgid "There is already a file named \"%s\". Do you want to replace it?" -msgstr "Там уже имеется файл с именем \"%s\". Вы хотите заменить его?" - -#: notebook/static/tree/js/notebooklist.js:1397 -msgid "Replace file" -msgstr "Заменить файл" diff --git a/notebook/i18n/ru_RU/LC_MESSAGES/nbui.po b/notebook/i18n/ru_RU/LC_MESSAGES/nbui.po deleted file mode 100644 index f4fde7888..000000000 --- a/notebook/i18n/ru_RU/LC_MESSAGES/nbui.po +++ /dev/null @@ -1,739 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-07 12:48-0500\n" -"PO-Revision-Date: 2020-07-06 11:05+0500\n" -"Language-Team: TranslAster \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" -"X-Generator: Poedit 2.3.1\n" -"Last-Translator: Dmitriy Q \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" -"Language: ru_RU\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "Вы запрашиваете страницу, которая не существует!" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "текущий режим" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "Файл" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "Новый" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "Сохранить" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "Переименовать" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "Загрузить" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "Редактировать" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "Поиск" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "Поиск & Замена" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "Сопоставления клавиш" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "По-умолчанию" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "Sublime Text" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "Вид" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "Показать/cкрыть логотип и название блокнота (над строкой меню)" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "Показать/скрыть заголовок" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "Показать/скрыть номера строк" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "Язык" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "Ошибка в:" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "Пароль или токен:" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "Пароль:" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "Вход" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "Без входа недоступно, вы не должны видеть эту страницу." - -#: notebook/templates/logout.html:24 -#, python-format -msgid "Proceed to the dashboard" -msgstr "Перейдите к панели мониторинга" - -#: notebook/templates/logout.html:26 -#, python-format -msgid "Proceed to the login page" -msgstr "Перейдите к странице входа" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "Меню" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "Ядро" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "Этот блокнот только для чтения" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "Новый блокнот" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "Открывает новое окно с видом панели мониторинга" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "Открыть..." - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "Откройте копию содержимого этого блокнота и запустите новое ядро" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "Сделать копию..." - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "Переименовать..." - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "Сохранение и контрольная точка" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "Вернуться к контрольной точке" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "Предпросмотр печати" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "Скачать как" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "Notebook (.ipynb)" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "Скрипт" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "HTML (.html)" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "Markdown (.md)" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "reST (.rst)" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "LaTeX (.tex)" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "PDF через LaTeX (.pdf)" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "Использовать как" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "Доверять выводу этого блокнота" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "Доверять блокноту" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "Выключить ядро этого блокнота и закрыть это окно" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "Закрыть и остановить" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "Вырезать ячейки" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "Копировать ячейки" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "Вставить ячейки выше" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "Вставить ячейки ниже" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "Вставить ячейки & заменить" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "Удалить ячейки" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "Отменить удаление ячеек" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "Разбить ячейку" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "Объединить с ячейкой выше" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "Объединить с ячейкой ниже" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "Переместить ячейку выше" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "Переместить ячейку ниже" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "Редактировать метаданные блокнота" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "Поиск и замена" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "Вырезать вложения ячейки" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "Копировать вложения ячейки" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "Вставить вложения ячейки" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "Вставить изображение" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "Показать/скрыть значки действий (ниже строки меню)" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "Показать/скрыть панель мониторинга" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "Показать/скрыть номера строк в ячейках" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "Панель инструментов ячейки" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "Вставка" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "Вставьте пустую ячейку кода над текущей активной ячейкой" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "Вставить ячейку выше" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "Вставьте пустую ячейку кода под текущей активной ячейкой" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "Вставить ячейку ниже" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "Ячейка" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "Запустить эту ячейку и переместить курсор на следующую" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "Запустить ячейки" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "Запустить эту ячейку, выбрать ниже" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "Запустить ячейки и выбрать ниже" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "Запустить эту ячейку, вставить ниже" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "Запустить ячейки и вставить ниже" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "Запустить все ячейки в этом блокноте" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "Запустить всё" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "Запустите все ячейки выше (но не включая) этой ячейки" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "Запустить всё выше" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "Запустить эту ячейку и все ячейки под ней" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "Запустить всё ниже" - -#: notebook/templates/notebook.html:205 -msgid "" -"All cells in the notebook have a cell type. By default, new cells are " -"created as 'Code' cells" -msgstr "" -"Все ячейки в блокноте имеют определенный тип ячеек. По умолчанию новые " -"ячейки создаются как ячейки \"Код\"" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "Тип ячейки" - -#: notebook/templates/notebook.html:209 -msgid "" -"Contents will be sent to the kernel for execution, and output will display " -"in the footer of cell" -msgstr "" -"Содержимое будет отправлено ядру для выполнения, а выходные данные будут " -"отображаться в нижнем колонтитуле ячейки" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "" -"Содержимое будет отображаться в формате HTML и служить пояснительным " -"текстом" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "Содержимое будет проходить через nbconvert неизмененным" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "Необработанный NBConvert" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "Текущий вывод" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "Показать/скрыть вывод текущей ячейки" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "Триггер" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "Прокрутить вывод текущей ячейки" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "Триггер скроллинга" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "Очистите выходные данные текущей ячейки" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "Очистка" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "Весь вывод" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "Скрыть/показать вывод всех ячеек" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "Прокрутите вывод всех ячеек" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "Очистите выходные данные всех ячеек" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "Отправить прерывание клавиатуры (CTRL-C) ядру" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "Прервать" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "Перезапустить ядро" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "Перезапуск" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "Перезапустить ядро и очистить все выходные данные" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "Перезапустить & очистить вывод" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "Перезапустить ядро и перезапустить блокнот" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "Перезапустить & Запустить всё" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "Переподключение к ядру" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "Переподключение" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "Изменение ядра" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "Справка" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "Краткий обзор пользовательского интерфейса блокнота" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "Обзор пользовательского интерфейса" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "Открывает инструмент со всеми сочетаниями клавиш" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "Сочетания клавиш" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "Открывает диалог, позволяющий редактировать сочетания клавиш" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "Редактировать сочетания клавиш" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "Справка по блокноту" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "Открыть в новом окне" - -#: notebook/templates/notebook.html:319 -msgid "About Jupyter Notebook" -msgstr "О блокноте Jupyter" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "О программе" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "Блокнот Jupyter требует JavaScript." - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "Пожалуйста, позвольте продолжить работу. " - -#: notebook/templates/page.html:121 -msgid "dashboard" -msgstr "панель мониторинга" - -#: notebook/templates/page.html:132 -msgid "Logout" -msgstr "Разлогиниться" - -#: notebook/templates/page.html:134 -msgid "Login" -msgstr "Вход" - -#: notebook/templates/tree.html:23 notebook/templates/tree.html:101 -msgid "Files" -msgstr "Файлы" - -#: notebook/templates/tree.html:24 notebook/templates/tree.html:100 -msgid "Running" -msgstr "Запустить" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "Кластеры" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "Выберите элементы для выполнения действий над ними." - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "Копировать выбранное" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "Скопировать" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "Переименовать выделенное" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "Переместить выделенное" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "Переместить" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "Скачать выбранное" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "Выключить выбранный(-е) блокнот(ы)" - -#: notebook/templates/notebook.html:278 notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "Выключение" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "Просмотр выбранного" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "Редактировать выделенное" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "Удалить выделенное" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "Нажмите, чтобы найти файл для загрузки." - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "Загрузить" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "Текстовый файл" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "Папка" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "Терминал" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "Терминалы недоступны" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "Обновить список блокнотов" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "Выбрать всё / ничего" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "Выбрать..." - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "Выбрать все папки" - -#: notebook/templates/tree.html:98 -msgid "Folders" -msgstr "Папки" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "Выбрать все блокноты" - -#: notebook/templates/tree.html:99 -msgid "All Notebooks" -msgstr "Все блокноты" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "Запустить выбранные блокноты" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "Выбрать все файлы" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "Последнее изменение" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "Название" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "Текущие запущенные процессы Jupyter" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "Обновить список запущенных" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "Эти терминалы не запущены." - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "Терминалы недоступны." - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "Блокноты" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "Эти блокноты не запущены." - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "Вкладка кластеров обеспечивается оболочкой IPython параллельно." - -#: notebook/templates/tree.html:179 -msgid "" -"See 'IPython parallel' for installation details." -msgstr "" -"Смотрите 'IPython " -"parallel' для подробной информации об установке." diff --git a/notebook/i18n/ru_RU/LC_MESSAGES/notebook.po b/notebook/i18n/ru_RU/LC_MESSAGES/notebook.po deleted file mode 100644 index 6d9bc08fb..000000000 --- a/notebook/i18n/ru_RU/LC_MESSAGES/notebook.po +++ /dev/null @@ -1,621 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-07-08 21:52-0500\n" -"PO-Revision-Date: 2020-07-06 17:38+0500\n" -"Language-Team: TranslAster \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" -"X-Generator: Poedit 2.3.1\n" -"Last-Translator: Dmitriy Q \n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" -"Language: ru_RU\n" - -#: notebook/notebookapp.py:53 -msgid "The Jupyter Notebook requires tornado >= 4.0" -msgstr "Для Jupyter Notebook требуется tornado >= 4.0" - -#: notebook/notebookapp.py:57 -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "Для Jupyter Notebook требуется tornado >= 4.0, но у вас < 1.1.0" - -#: notebook/notebookapp.py:59 -#, python-format -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have %s" -msgstr "Для Jupyter Notebook требуется tornado >= 4.0, но у вас %s" - -#: notebook/notebookapp.py:209 -msgid "The `ignore_minified_js` flag is deprecated and no longer works." -msgstr "Флаг `ignore_minified_js` устарел и больше не работает." - -#: notebook/notebookapp.py:210 -#, python-format -msgid "" -"Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "" -"В качестве альтернативы используйте `%s` при работе с блокнотами Javascript " -"и LESS" - -#: notebook/notebookapp.py:211 -msgid "" -"The `ignore_minified_js` flag is deprecated and will be removed in Notebook " -"6.0" -msgstr "Флаг `ignore_minified_js` устарел и будет удален в Notebook 6.0" - -#: notebook/notebookapp.py:389 -msgid "List currently running notebook servers." -msgstr "Список запущенных в данный момент серверов блокнотов." - -#: notebook/notebookapp.py:393 -msgid "Produce machine-readable JSON output." -msgstr "Произведите машиночитаемый вывод JSON." - -#: notebook/notebookapp.py:397 -msgid "" -"If True, each line of output will be a JSON object with the details from the " -"server info file." -msgstr "" -"Если True, то каждая строка вывода будет представлять собой объект JSON с " -"подробностями из файла информации сервера." - -#: notebook/notebookapp.py:402 -msgid "Currently running servers:" -msgstr "В настоящее время работают сервера:" - -#: notebook/notebookapp.py:419 -msgid "Don't open the notebook in a browser after startup." -msgstr "Не открывайте блокнот в браузере после запуска." - -#: notebook/notebookapp.py:423 -msgid "" -"DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "" -"ОТКЛЮЧЕНО: используйте %pylab или %matplotlib в блокноте чтобы включить " -"matplotlib." - -#: notebook/notebookapp.py:439 -msgid "Allow the notebook to be run from root user." -msgstr "Разрешить запускать блокнот от пользователя root." - -#: notebook/notebookapp.py:470 -msgid "" -"The Jupyter HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an " -"HTML5/Javascript Notebook client." -msgstr "" -"The Jupyter HTML Notebook.\n" -" \n" -" Запускает сервер HTML Notebook на базе Tornado, обслуживающий клиент " -"HTML5/Javascript Notebook." - -#: notebook/notebookapp.py:509 -msgid "" -"Deprecated: Use minified JS file or not, mainly use during dev to avoid JS " -"recompilation" -msgstr "" -"Устарело: используйте уменьшенный файл JS или нет, в основном используется " -"во время разработки чтобы избежать перекомпиляции JS" - -#: notebook/notebookapp.py:540 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "Установка контроль-доступа-разрешенные-учетные_данные: заголовок true" - -#: notebook/notebookapp.py:544 -msgid "Whether to allow the user to run the notebook as root." -msgstr "Следует ли разрешить пользователю запускать блокнот от имени root." - -#: notebook/notebookapp.py:548 -msgid "The default URL to redirect to from `/`" -msgstr "URL-адрес по умолчанию для перенаправления на `/`" - -#: notebook/notebookapp.py:552 -msgid "The IP address the notebook server will listen on." -msgstr "IP-адрес, который будет прослушиваться сервером блокнота." - -#: notebook/notebookapp.py:565 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "" -"Невозможно привязаться к localhost, используйте 127.0.0.1 в качестве ip-" -"адреса по умолчанию\n" -"%s" - -#: notebook/notebookapp.py:579 -msgid "The port the notebook server will listen on." -msgstr "Порт сервера блокнотов для прослушивания." - -#: notebook/notebookapp.py:583 -msgid "" -"The number of additional ports to try if the specified port is not available." -msgstr "" -"Количество дополнительных портов, которые нужно попробовать, если указанный " -"порт недоступен." - -#: notebook/notebookapp.py:587 -msgid "The full path to an SSL/TLS certificate file." -msgstr "Полный путь к файлу сертификата с SSL/TLS." - -#: notebook/notebookapp.py:591 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "Полный путь к файлу приватного ключа для использования с SSL/TLS." - -#: notebook/notebookapp.py:595 -msgid "" -"The full path to a certificate authority certificate for SSL/TLS client " -"authentication." -msgstr "" -"Полный путь к сертификату центра сертификации для SSL/TLS аутентификации " -"клиента." - -#: notebook/notebookapp.py:599 -msgid "The file where the cookie secret is stored." -msgstr "Файл, в котором хранится пароль cookie." - -#: notebook/notebookapp.py:628 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "Запись пароля cookie сервера блокнота в %s" - -#: notebook/notebookapp.py:635 -#, python-format -msgid "Could not set permissions on %s" -msgstr "Не удалось установить разрешения для %s" - -#: notebook/notebookapp.py:640 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which " -"is NOT RECOMMENDED.\n" -" " -msgstr "" -"Токен, используемый для проверки подлинности при первом подключении к " -"серверу.\n" -"\n" -" Когда пароль не включен,\n" -" по умолчанию генерируется новый случайный токен.\n" -"\n" -" Установка пустой строки полностью отключает аутентификацию, что НЕ " -"РЕКОМЕНДУЕТСЯ.\n" -" " - -#: notebook/notebookapp.py:650 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "" -"Одноразовый токен, используемый для открытия в браузере. \n" -" После использования этот токен не может быть использован снова.\n" -" " - -#: notebook/notebookapp.py:726 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser." -"open`.\n" -" The behaviour is not guaranteed, but depends on browser support. " -"Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" -"Укажите где открывать блокнот при запуске. Это \"новый\"\n" -" аргумент, передаваемый для стандартного метода библиотек `webbrowser." -"open`.\n" -" Поведение не гарантируется, но зависит от поддержки браузера. " -"Допустимыми\n" -" значениями являются:\n" -" 2 открывает новую вкладку,\n" -" 1 открывает новое окно,\n" -" 0 открывается в существующем окне.\n" -" См. документацию `webbrowser.open` для получения подробной " -"информации.\n" -" " - -#: notebook/notebookapp.py:737 -msgid "DEPRECATED, use tornado_settings" -msgstr "УСТАРЕЛО - используйте tornado_settings" - -#: notebook/notebookapp.py:742 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "" -"\n" -" web app_settings устарел, используйте tornado_settings.\n" - -#: notebook/notebookapp.py:746 -msgid "" -"Supply overrides for the tornado.web.Application that the Jupyter notebook " -"uses." -msgstr "" -"Перекрывает поставки для tornado.web. Приложение, использующее блокнот " -"Jupyter." - -#: notebook/notebookapp.py:750 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler." -"get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options " -"for details.\n" -" " -msgstr "" -"\n" -" Установите параметры сжатия tornado для соединений websocket.\n" -"\n" -" Это значение будет возвращено из :meth: 'WebSocketHandler." -"get_compression_options`.\n" -" None (по умолчанию) отключит сжатие.\n" -" Диктат (даже пустой) будет включать сжатие.\n" -"\n" -" Смотрите документы tornado для WebSocketHandler." -"get_compression_options для получения подробной информации.\n" -" " - -#: notebook/notebookapp.py:761 -msgid "" -"Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" -"Переопределение поставок для terminado. В настоящее время поддерживается " -"только \"shell_command\"." - -#: notebook/notebookapp.py:764 -msgid "" -"Extra keyword arguments to pass to `set_secure_cookie`. See tornado's " -"set_secure_cookie docs for details." -msgstr "" -"Дополнительные аргументы ключевого слова для передачи в `set_secure_cookie`. " -"Подробнее см. документацию set_secure_cookie для tornado." - -#: notebook/notebookapp.py:768 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" -"Предоставьте параметры SSL для HTTPServer tornado.\n" -" Подробности смотрите в документации tornado." - -#: notebook/notebookapp.py:772 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "Предоставьте дополнительные аргументы, передаваемые в среду Jinja." - -#: notebook/notebookapp.py:776 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "" -"Дополнительные переменные для предоставления шаблонам jinja при рендеринге." - -#: notebook/notebookapp.py:812 -msgid "DEPRECATED use base_url" -msgstr "УСТАРЕЛО - используйте base_url" - -#: notebook/notebookapp.py:816 -msgid "base_project_url is deprecated, use base_url" -msgstr "base_project_url устарел - используйте base_url" - -#: notebook/notebookapp.py:832 -msgid "Path to search for custom.js, css" -msgstr "Путь для поиска custom.js, css" - -#: notebook/notebookapp.py:844 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "" -"Дополнительные пути для поиска обслуживающих шаблонов jinja.\n" -"\n" -" Может использоваться для переопределения шаблонов из notebook." -"templates." - -#: notebook/notebookapp.py:855 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "дополнительные пути для поиска расширений блокнота Javascript" - -#: notebook/notebookapp.py:900 -#, python-format -msgid "Using MathJax: %s" -msgstr "Использование MathJax: %s" - -#: notebook/notebookapp.py:903 -msgid "The MathJax.js configuration file that is to be used." -msgstr "Использовать файл конфигурации MathJax.js." - -#: notebook/notebookapp.py:908 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "Использование файла конфигурации MathJax: %s" - -#: notebook/notebookapp.py:914 -msgid "The notebook manager class to use." -msgstr "Используемый класс менеджера блокнотов." - -#: notebook/notebookapp.py:920 -msgid "The kernel manager class to use." -msgstr "Используемый класс менеджера ядра." - -#: notebook/notebookapp.py:926 -msgid "The session manager class to use." -msgstr "Класс менеджера сеансов для использования." - -#: notebook/notebookapp.py:932 -msgid "The config manager class to use" -msgstr "Класс менеджера конфигурации для использования" - -#: notebook/notebookapp.py:953 -msgid "The login handler class to use." -msgstr "Используемый класс обработчика входа в систему." - -#: notebook/notebookapp.py:960 -msgid "The logout handler class to use." -msgstr "Используемый класс обработчика выхода из системы." - -#: notebook/notebookapp.py:964 -msgid "" -"Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-" -"For headerssent by the upstream reverse proxy. Necessary if the proxy " -"handles SSL" -msgstr "" -"Стоит ли доверять или нет Х-схеме/х-перенаправлению-прото и X-реал-ip/х-" -"перенаправлению-для заголовков, загружаемых по потоку обратного прокси-" -"сервера. Необходимо, если прокси обрабатывает SSL" - -#: notebook/notebookapp.py:976 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable " -"matplotlib.\n" -" " -msgstr "" -"\n" -" Отключено: используйте %pylab или %matplotlib в блокноте чтобы " -"включить matplotlib.\n" -" " - -#: notebook/notebookapp.py:988 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "Поддержка указания --pylab в командной строке была удалена." - -#: notebook/notebookapp.py:990 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "" -"Пожалуйста, используйте `%pylab{0}` или `%matplotlib{0}` в самом блокноте." - -#: notebook/notebookapp.py:995 -msgid "The directory to use for notebooks and kernels." -msgstr "Каталог, используемый для блокнотов и ядер." - -#: notebook/notebookapp.py:1018 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "Нет такого блокнота: '%r'" - -#: notebook/notebookapp.py:1031 -msgid "DEPRECATED use the nbserver_extensions dict instead" -msgstr "УСТАРЕЛО - используйте nbserver_extensions вместо диктата" - -#: notebook/notebookapp.py:1036 -msgid "server_extensions is deprecated, use nbserver_extensions" -msgstr "server_extensions устарело - используйте nbserver_extensions" - -#: notebook/notebookapp.py:1040 -msgid "" -"Dict of Python modules to load as notebook server extensions.Entry values " -"can be used to enable and disable the loading ofthe extensions. The " -"extensions will be loaded in alphabetical order." -msgstr "" -"Dict модулей Python для загрузки в качестве серверных расширений блокнотов. " -"Введенные значения можно использовать для включения и отключения загрузки " -"расширений. Расширения будут загружены в алфавитном порядке." - -#: notebook/notebookapp.py:1049 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "" -"Повторно поднимаемые исключения, встречающиеся при загрузке серверных " -"расширений?" - -#: notebook/notebookapp.py:1052 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" -"(сообщ/сек)\n" -" Максимальная скорость отправки сообщений на iopub, прежде\n" -" чем они будут ограничены." - -#: notebook/notebookapp.py:1056 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they " -"are\n" -" limited." -msgstr "" -"(байт/сек)\n" -" Максимальная скорость отправки потока вывода на iopub, прежде\n" -" чем он будет ограничен." - -#: notebook/notebookapp.py:1060 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "" -"(сек) Окно времени, используемое для \n" -" проверки ограничений скорости передачи сообщений и данных." - -#: notebook/notebookapp.py:1071 -#, python-format -msgid "No such file or directory: %s" -msgstr "Нет такого файла или каталога: %s" - -#: notebook/notebookapp.py:1141 -msgid "Notebook servers are configured to only be run with a password." -msgstr "Серверы блокнотов настроены на работу только с паролем." - -#: notebook/notebookapp.py:1142 -msgid "Hint: run the following command to set a password" -msgstr "Подсказка: выполните следующую команду, чтобы установить пароль" - -#: notebook/notebookapp.py:1143 -msgid "\t$ python -m notebook.auth password" -msgstr "\t$ python -m notebook.auth password" - -#: notebook/notebookapp.py:1181 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "Порт %i уже используется, попробуйте другой порт." - -#: notebook/notebookapp.py:1184 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "Разрешение на прослушивание порта %i отклонено" - -#: notebook/notebookapp.py:1193 -msgid "" -"ERROR: the notebook server could not be started because no available port " -"could be found." -msgstr "" -"ОШИБКА: не удалось запустить сервер блокнота, так как не удалось найти " -"доступный порт." - -#: notebook/notebookapp.py:1199 -msgid "[all ip addresses on your system]" -msgstr "[все ip-адреса в вашей системе]" - -#: notebook/notebookapp.py:1223 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "Терминалы недоступны (ошибка: %s)" - -#: notebook/notebookapp.py:1259 -msgid "interrupted" -msgstr "прервано" - -#: notebook/notebookapp.py:1261 -msgid "y" -msgstr "д" - -#: notebook/notebookapp.py:1262 -msgid "n" -msgstr "н" - -#: notebook/notebookapp.py:1263 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "Выключить этот сервер блокнотов (%s/[%s])? " - -#: notebook/notebookapp.py:1269 -msgid "Shutdown confirmed" -msgstr "Выключение подтверждено" - -#: notebook/notebookapp.py:1273 -msgid "No answer for 5s:" -msgstr "Нет ответа уже 5с:" - -#: notebook/notebookapp.py:1274 -msgid "resuming operation..." -msgstr "возобновить работу..." - -#: notebook/notebookapp.py:1282 -#, python-format -msgid "received signal %s, stopping" -msgstr "получен сигнал %s, остановка" - -#: notebook/notebookapp.py:1338 -#, python-format -msgid "Error loading server extension %s" -msgstr "Ошибка загрузки расширения сервера %s" - -#: notebook/notebookapp.py:1369 -#, python-format -msgid "Shutting down %d kernels" -msgstr "Выключить %d ядер" - -#: notebook/notebookapp.py:1375 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "%d активное ядро" -msgstr[1] "%d активных ядра" -msgstr[2] "%d активных ядер" - -#: notebook/notebookapp.py:1379 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"\r%s" -msgstr "" -"Jupyter Notebook запущен на:\n" -"\r%s" - -#: notebook/notebookapp.py:1426 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "" -"Запуск от имени root не рекомендуется. Используйте --allow-root для обхода." - -#: notebook/notebookapp.py:1432 -msgid "" -"Use Control-C to stop this server and shut down all kernels (twice to skip " -"confirmation)." -msgstr "" -"Используйте Control-C, для остановки этого сервера и выключения всех ядер " -"(дважды, чтобы пропустить подтверждение)." - -#: notebook/notebookapp.py:1434 -msgid "" -"Welcome to Project Jupyter! Explore the various tools available and their " -"corresponding documentation. If you are interested in contributing to the " -"platform, please visit the communityresources section at http://jupyter.org/" -"community.html." -msgstr "" -"Добро пожаловать в проект Jupyter! Изучите различные доступные инструменты и " -"соответствующую им документацию. Если вы заинтересованы в том, чтобы внести " -"свой вклад в платформу, пожалуйста, посетите раздел ресурсов сообщества по " -"адресу http://jupyter.org/community.html." - -#: notebook/notebookapp.py:1445 -#, python-format -msgid "No web browser found: %s." -msgstr "Веб-браузер не найден: %s." - -#: notebook/notebookapp.py:1450 -#, python-format -msgid "%s does not exist" -msgstr "%s не существует" - -#: notebook/notebookapp.py:1484 -msgid "Interrupted..." -msgstr "Прерывание..." - -#: notebook/services/contents/filemanager.py:506 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "Обслуживание блокнотов из локального каталога: %s" - -#: notebook/services/contents/manager.py:68 -msgid "Untitled" -msgstr "Без названия" diff --git a/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po b/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po deleted file mode 100644 index 0891ff5ad..000000000 --- a/notebook/i18n/zh_CN/LC_MESSAGES/nbjs.po +++ /dev/null @@ -1,1978 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -# Universal translation: cell=单元格; kernal=内核; don't translate notebook whenever referring to Jupyter Notebook -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-08-25 02:53-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.0\n" - -#: notebook/static/base/js/dialog.js:161 -msgid "Manually edit the JSON below to manipulate the metadata for this cell." -msgstr "手动编辑下面的 JSON 代码来修改块元数据。" - -#: notebook/static/base/js/dialog.js:163 -msgid "Manually edit the JSON below to manipulate the metadata for this notebook." -msgstr "手动编辑下面的 JSON 代码来修改笔记本元数据。" - -#: notebook/static/base/js/dialog.js:165 -msgid " We recommend putting custom metadata attributes in an appropriately named substructure, so they don't conflict with those of others." -msgstr "我们建议将自定义的元数据属性放入适当的子结构中,这样就不会与其他的子结构发生冲突。" - -#: notebook/static/base/js/dialog.js:180 -msgid "Edit the metadata" -msgstr "编辑元数据" - -#: notebook/static/base/js/dialog.js:202 -msgid "Edit Notebook Metadata" -msgstr "编辑Notebook元数据" - -#: notebook/static/base/js/dialog.js:204 -msgid "Edit Cell Metadata" -msgstr "编辑单元格元数据" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/notebook.js:485 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:863 -#: notebook/static/tree/js/notebooklist.js:1420 -msgid "Cancel" -msgstr "取消" - -#: notebook/static/base/js/dialog.js:208 -msgid "Edit" -msgstr "编辑" - -#: notebook/static/base/js/dialog.js:208 -#: notebook/static/notebook/js/kernelselector.js:278 -#: notebook/static/notebook/js/mathjaxutils.js:42 -#: notebook/static/notebook/js/notebook.js:479 -#: notebook/static/notebook/js/notificationarea.js:186 -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/newnotebook.js:97 -#: notebook/static/tree/js/notebooklist.js:863 -msgid "OK" -msgstr "确定" - -#: notebook/static/base/js/dialog.js:208 -msgid "Apply" -msgstr "应用" - -#: notebook/static/base/js/dialog.js:225 -msgid "WARNING: Could not save invalid JSON." -msgstr "警告: 不能保存无效的JSON。" - -#: notebook/static/base/js/dialog.js:247 -msgid "There are no attachments for this cell." -msgstr "这个单元格没有附件。" - -#: notebook/static/base/js/dialog.js:250 -msgid "Current cell attachments" -msgstr "当前单元格附件" - -#: notebook/static/base/js/dialog.js:259 -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:46 -msgid "Attachments" -msgstr "附件" - -#: notebook/static/base/js/dialog.js:283 -msgid "Restore" -msgstr "重新保存" - -#: notebook/static/base/js/dialog.js:293 -#: notebook/static/tree/js/notebooklist.js:1022 -msgid "Delete" -msgstr "删除" - -#: notebook/static/base/js/dialog.js:342 notebook/static/base/js/dialog.js:386 -msgid "Edit attachments" -msgstr "编辑附件" - -#: notebook/static/base/js/dialog.js:348 -msgid "Edit Notebook Attachments" -msgstr "编辑笔记本附件" - -#: notebook/static/base/js/dialog.js:350 -msgid "Edit Cell Attachments" -msgstr "编辑单元格附件" - -#: notebook/static/base/js/dialog.js:373 -msgid "Select a file to insert." -msgstr "选择文件插入" - -#: notebook/static/base/js/dialog.js:399 -msgid "Select a file" -msgstr "选择文件" - -#: notebook/static/notebook/js/about.js:14 -msgid "You are using Jupyter notebook." -msgstr "您正在使用 Jupyter Notebook。" - -#: notebook/static/notebook/js/about.js:16 -msgid "The version of the notebook server is: " -msgstr "该 notebook 服务的版本是:" - -#: notebook/static/notebook/js/about.js:22 -msgid "The server is running on this version of Python:" -msgstr "该服务运行中使用的 Python 版本为:" - -#: notebook/static/notebook/js/about.js:25 -msgid "Waiting for kernel to be available..." -msgstr "等待内核可用..." - -#: notebook/static/notebook/js/about.js:27 -msgid "Server Information:" -msgstr "服务信息:" - -#: notebook/static/notebook/js/about.js:29 -msgid "Current Kernel Information:" -msgstr "当前内核信息:" - -#: notebook/static/notebook/js/about.js:32 -msgid "Could not access sys_info variable for version information." -msgstr "无法访问 sys_info 变量来获取版本信息。" - -#: notebook/static/notebook/js/about.js:34 -msgid "Cannot find sys_info!" -msgstr "找不到 sys_info!" - -#: notebook/static/notebook/js/about.js:38 -msgid "About Jupyter Notebook" -msgstr "关于 Jupyter Notebook" - -#: notebook/static/notebook/js/about.js:47 -msgid "unable to contact kernel" -msgstr "不能连接到内核" - -#: notebook/static/notebook/js/actions.js:69 -msgid "toggle rtl layout" -msgstr "切换 RTL 布局" - -#: notebook/static/notebook/js/actions.js:70 -msgid "Toggle the screen directionality between left-to-right and right-to-left" -msgstr "切换左至右或右至左的屏幕方向" - -#: notebook/static/notebook/js/actions.js:76 -msgid "edit command mode keyboard shortcuts" -msgstr "编辑命令模式键盘快捷键" - -#: notebook/static/notebook/js/actions.js:77 -msgid "Open a dialog to edit the command mode keyboard shortcuts" -msgstr "打开窗口来编辑快捷键" - -#: notebook/static/notebook/js/actions.js:97 -msgid "restart kernel" -msgstr "重启内核" - -#: notebook/static/notebook/js/actions.js:98 -msgid "restart the kernel (no confirmation dialog)" -msgstr "重启内核(无确认对话框)" - -#: notebook/static/notebook/js/actions.js:106 -msgid "confirm restart kernel" -msgstr "确定重启内核" - -#: notebook/static/notebook/js/actions.js:107 -msgid "restart the kernel (with dialog)" -msgstr "重启内核(带确认对话框)" - -#: notebook/static/notebook/js/actions.js:113 -msgid "restart kernel and run all cells" -msgstr "重启内核并且运行所有单元格" - -#: notebook/static/notebook/js/actions.js:114 -msgid "restart the kernel, then re-run the whole notebook (no confirmation dialog)" -msgstr "重启服务,然后重新运行整个笔记本(无确认对话框)" - -#: notebook/static/notebook/js/actions.js:120 -msgid "confirm restart kernel and run all cells" -msgstr "确认重启内核并且运行所有单元格" - -#: notebook/static/notebook/js/actions.js:121 -msgid "restart the kernel, then re-run the whole notebook (with dialog)" -msgstr "重启内核, 然后重新运行整个notebook(带确认对话框)" - -#: notebook/static/notebook/js/actions.js:127 -msgid "restart kernel and clear output" -msgstr "重启内核并且清空输出" - -#: notebook/static/notebook/js/actions.js:128 -msgid "restart the kernel and clear all output (no confirmation dialog)" -msgstr "重启内核并且清空所有输出(无确认对话框)" - -#: notebook/static/notebook/js/actions.js:134 -msgid "confirm restart kernel and clear output" -msgstr "确认重启内核并且清空输出" - -#: notebook/static/notebook/js/actions.js:135 -msgid "restart the kernel and clear all output (with dialog)" -msgstr "重启内核并且清空所有输出(带确认对话框)" - -#: notebook/static/notebook/js/actions.js:142 -#: notebook/static/notebook/js/actions.js:143 -msgid "interrupt the kernel" -msgstr "中断内核" - -#: notebook/static/notebook/js/actions.js:150 -msgid "run cell and select next" -msgstr "运行单元格并且选择下一个单元格" - -#: notebook/static/notebook/js/actions.js:152 -msgid "run cell, select below" -msgstr "运行单元格, 选择下面的单元格" - -#: notebook/static/notebook/js/actions.js:159 -#: notebook/static/notebook/js/actions.js:160 -msgid "run selected cells" -msgstr "运行选中的单元格" - -#: notebook/static/notebook/js/actions.js:167 -#: notebook/static/notebook/js/actions.js:168 -msgid "run cell and insert below" -msgstr "运行单元格并且在下面插入单元格" - -#: notebook/static/notebook/js/actions.js:175 -#: notebook/static/notebook/js/actions.js:176 -msgid "run all cells" -msgstr "运行所有的单元格" - -#: notebook/static/notebook/js/actions.js:183 -#: notebook/static/notebook/js/actions.js:184 -msgid "run all cells above" -msgstr "运行上面所有的单元格" - -#: notebook/static/notebook/js/actions.js:190 -#: notebook/static/notebook/js/actions.js:191 -msgid "run all cells below" -msgstr "运行下面所有的单元格" - -#: notebook/static/notebook/js/actions.js:197 -#: notebook/static/notebook/js/actions.js:198 -msgid "enter command mode" -msgstr "进入命令行模式" - -#: notebook/static/notebook/js/actions.js:205 -#: notebook/static/notebook/js/actions.js:206 -msgid "insert image" -msgstr "插入图片" - -#: notebook/static/notebook/js/actions.js:213 -#: notebook/static/notebook/js/actions.js:214 -msgid "cut cell attachments" -msgstr "剪切单元格的附件" - -#: notebook/static/notebook/js/actions.js:221 -#: notebook/static/notebook/js/actions.js:222 -msgid "copy cell attachments" -msgstr "复制单元格的附件" - -#: notebook/static/notebook/js/actions.js:229 -#: notebook/static/notebook/js/actions.js:230 -msgid "paste cell attachments" -msgstr "粘贴单元格的附件" - -#: notebook/static/notebook/js/actions.js:237 -#: notebook/static/notebook/js/actions.js:238 -msgid "split cell at cursor" -msgstr "在光标处分割单元格" - -#: notebook/static/notebook/js/actions.js:245 -#: notebook/static/notebook/js/actions.js:246 -msgid "enter edit mode" -msgstr "进入编辑模式" - -#: notebook/static/notebook/js/actions.js:253 -msgid "select previous cell" -msgstr "选择上一个单元格" - -#: notebook/static/notebook/js/actions.js:254 -msgid "select cell above" -msgstr "选择上面的单元格" - -#: notebook/static/notebook/js/actions.js:265 -msgid "select next cell" -msgstr "选择下一个单元格" - -#: notebook/static/notebook/js/actions.js:266 -msgid "select cell below" -msgstr "选择下面的单元格" - -#: notebook/static/notebook/js/actions.js:277 -msgid "extend selection above" -msgstr "扩展上面的单元格" - -#: notebook/static/notebook/js/actions.js:278 -msgid "extend selected cells above" -msgstr "扩展上面选择的单元格" - -#: notebook/static/notebook/js/actions.js:289 -msgid "extend selection below" -msgstr "扩展下面的单元格" - -#: notebook/static/notebook/js/actions.js:290 -msgid "extend selected cells below" -msgstr "扩展下面选择的单元格" - -#: notebook/static/notebook/js/actions.js:301 -#: notebook/static/notebook/js/actions.js:302 -msgid "cut selected cells" -msgstr "剪切选择的单元格" - -#: notebook/static/notebook/js/actions.js:312 -#: notebook/static/notebook/js/actions.js:313 -msgid "copy selected cells" -msgstr "复制选择的单元格" - -#: notebook/static/notebook/js/actions.js:327 -#: notebook/static/notebook/js/actions.js:328 -msgid "paste cells above" -msgstr "粘贴到上面" - -#: notebook/static/notebook/js/actions.js:335 -#: notebook/static/notebook/js/actions.js:336 -msgid "paste cells below" -msgstr "粘贴到下面" - -#: notebook/static/notebook/js/actions.js:344 -#: notebook/static/notebook/js/actions.js:345 -msgid "insert cell above" -msgstr "在上面插入单元格" - -#: notebook/static/notebook/js/actions.js:354 -#: notebook/static/notebook/js/actions.js:355 -msgid "insert cell below" -msgstr "在下面插入单元格" - -#: notebook/static/notebook/js/actions.js:365 -#: notebook/static/notebook/js/actions.js:366 -msgid "change cell to code" -msgstr "把单元格变成代码快" - -#: notebook/static/notebook/js/actions.js:373 -#: notebook/static/notebook/js/actions.js:374 -msgid "change cell to markdown" -msgstr "把单元格变成 Markdown" - -#: notebook/static/notebook/js/actions.js:381 -#: notebook/static/notebook/js/actions.js:382 -msgid "change cell to raw" -msgstr "清除单元格格式" - -#: notebook/static/notebook/js/actions.js:389 -#: notebook/static/notebook/js/actions.js:390 -msgid "change cell to heading 1" -msgstr "把单元格变成标题 1" - -#: notebook/static/notebook/js/actions.js:397 -#: notebook/static/notebook/js/actions.js:398 -msgid "change cell to heading 2" -msgstr "把单元格变成标题 2" - -#: notebook/static/notebook/js/actions.js:405 -#: notebook/static/notebook/js/actions.js:406 -msgid "change cell to heading 3" -msgstr "把单元格变成标题 3" - -#: notebook/static/notebook/js/actions.js:413 -#: notebook/static/notebook/js/actions.js:414 -msgid "change cell to heading 4" -msgstr "把单元格变成标题 4" - -#: notebook/static/notebook/js/actions.js:421 -#: notebook/static/notebook/js/actions.js:422 -msgid "change cell to heading 5" -msgstr "把单元格变成标题 5" - -#: notebook/static/notebook/js/actions.js:429 -#: notebook/static/notebook/js/actions.js:430 -msgid "change cell to heading 6" -msgstr "把单元格变成标题 6" - -#: notebook/static/notebook/js/actions.js:437 -msgid "toggle cell output" -msgstr "显示/隐藏单元格输出" - -#: notebook/static/notebook/js/actions.js:438 -msgid "toggle output of selected cells" -msgstr "显示/隐藏选定单元格的输出" - -#: notebook/static/notebook/js/actions.js:445 -msgid "toggle cell scrolling" -msgstr "切换单元格为滚动" - -#: notebook/static/notebook/js/actions.js:446 -msgid "toggle output scrolling of selected cells" -msgstr "切换选中单元格的输出为滚动" - -#: notebook/static/notebook/js/actions.js:453 -msgid "clear cell output" -msgstr "清空所有单元格输出" - -#: notebook/static/notebook/js/actions.js:454 -msgid "clear output of selected cells" -msgstr "清空已选择单元格的输出" - -#: notebook/static/notebook/js/actions.js:460 -msgid "move cells down" -msgstr "下移单元格" - -#: notebook/static/notebook/js/actions.js:461 -msgid "move selected cells down" -msgstr "下移选中单元格" - -#: notebook/static/notebook/js/actions.js:469 -msgid "move cells up" -msgstr "上移单元格" - -#: notebook/static/notebook/js/actions.js:470 -msgid "move selected cells up" -msgstr "上移选中单元格" - -#: notebook/static/notebook/js/actions.js:478 -#: notebook/static/notebook/js/actions.js:479 -msgid "toggle line numbers" -msgstr "切换行号" - -#: notebook/static/notebook/js/actions.js:486 -#: notebook/static/notebook/js/actions.js:487 -msgid "show keyboard shortcuts" -msgstr "显示键盘快捷键" - -#: notebook/static/notebook/js/actions.js:494 -msgid "delete cells" -msgstr "删除单元格" - -#: notebook/static/notebook/js/actions.js:495 -msgid "delete selected cells" -msgstr "删除选中单元格" - -#: notebook/static/notebook/js/actions.js:502 -#: notebook/static/notebook/js/actions.js:503 -msgid "undo cell deletion" -msgstr "撤销删除单元格" - -#: notebook/static/notebook/js/actions.js:512 -msgid "merge cell with previous cell" -msgstr "合并上一个单元格" - -#: notebook/static/notebook/js/actions.js:513 -msgid "merge cell above" -msgstr "合并上面的单元格" - -#: notebook/static/notebook/js/actions.js:519 -msgid "merge cell with next cell" -msgstr "合并下一个单元格" - -#: notebook/static/notebook/js/actions.js:520 -msgid "merge cell below" -msgstr "合并下面的单元格" - -#: notebook/static/notebook/js/actions.js:527 -#: notebook/static/notebook/js/actions.js:528 -msgid "merge selected cells" -msgstr "合并选中的单元格" - -#: notebook/static/notebook/js/actions.js:535 -msgid "merge cells" -msgstr "合并单元格" - -#: notebook/static/notebook/js/actions.js:536 -msgid "merge selected cells, or current cell with cell below if only one cell is selected" -msgstr "合并选中单元格, 如果只有一个单元格被选中" - -#: notebook/static/notebook/js/actions.js:549 -msgid "show command pallette" -msgstr "显示命令配置" - -#: notebook/static/notebook/js/actions.js:550 -msgid "open the command palette" -msgstr "打开命令配置" - -#: notebook/static/notebook/js/actions.js:557 -msgid "toggle all line numbers" -msgstr "切换所有行号" - -#: notebook/static/notebook/js/actions.js:558 -msgid "toggles line numbers in all cells, and persist the setting" -msgstr "在所有单元格中切换行号,并保持设置" - -#: notebook/static/notebook/js/actions.js:569 -msgid "show all line numbers" -msgstr "显示行号" - -#: notebook/static/notebook/js/actions.js:570 -msgid "show line numbers in all cells, and persist the setting" -msgstr "在所有单元格中显示行号,并保持设置" - -#: notebook/static/notebook/js/actions.js:579 -msgid "hide all line numbers" -msgstr "隐藏行号" - -#: notebook/static/notebook/js/actions.js:580 -msgid "hide line numbers in all cells, and persist the setting" -msgstr "隐藏行号并保持设置" - -#: notebook/static/notebook/js/actions.js:589 -msgid "toggle header" -msgstr "切换标题" - -#: notebook/static/notebook/js/actions.js:590 -msgid "switch between showing and hiding the header" -msgstr "切换显示和隐藏标题" - -#: notebook/static/notebook/js/actions.js:605 -#: notebook/static/notebook/js/actions.js:606 -msgid "show the header" -msgstr "显示标题" - -#: notebook/static/notebook/js/actions.js:615 -#: notebook/static/notebook/js/actions.js:616 -msgid "hide the header" -msgstr "隐藏标题" - -#: notebook/static/notebook/js/actions.js:646 -msgid "toggle toolbar" -msgstr "切换工具栏" - -#: notebook/static/notebook/js/actions.js:647 -msgid "switch between showing and hiding the toolbar" -msgstr "切换显示/隐藏工具栏" - -#: notebook/static/notebook/js/actions.js:660 -#: notebook/static/notebook/js/actions.js:661 -msgid "show the toolbar" -msgstr "显示工具栏" - -#: notebook/static/notebook/js/actions.js:669 -#: notebook/static/notebook/js/actions.js:670 -msgid "hide the toolbar" -msgstr "隐藏工具栏" - -#: notebook/static/notebook/js/actions.js:678 -#: notebook/static/notebook/js/actions.js:679 -msgid "close the pager" -msgstr "关闭分页器" - -#: notebook/static/notebook/js/actions.js:704 -msgid "ignore" -msgstr "忽略" - -#: notebook/static/notebook/js/actions.js:710 -#: notebook/static/notebook/js/actions.js:711 -msgid "move cursor up" -msgstr "光标上移" - -#: notebook/static/notebook/js/actions.js:731 -#: notebook/static/notebook/js/actions.js:732 -msgid "move cursor down" -msgstr "光标下移" - -#: notebook/static/notebook/js/actions.js:750 -#: notebook/static/notebook/js/actions.js:751 -msgid "scroll notebook down" -msgstr "向下滚动" - -#: notebook/static/notebook/js/actions.js:760 -#: notebook/static/notebook/js/actions.js:761 -msgid "scroll notebook up" -msgstr "向上滚动" - -#: notebook/static/notebook/js/actions.js:770 -msgid "scroll cell center" -msgstr "滚动单元格到中间" - -#: notebook/static/notebook/js/actions.js:771 -msgid "Scroll the current cell to the center" -msgstr "把当前单元格滚动到中间" - -#: notebook/static/notebook/js/actions.js:781 -msgid "scroll cell top" -msgstr "滚动单元格到顶" - -#: notebook/static/notebook/js/actions.js:782 -msgid "Scroll the current cell to the top" -msgstr "将当前单元格滚动到顶部" - -#: notebook/static/notebook/js/actions.js:792 -msgid "duplicate notebook" -msgstr "制作笔记本副本" - -#: notebook/static/notebook/js/actions.js:793 -msgid "Create and open a copy of the current notebook" -msgstr "创建并打开当前笔记本的一个副本" - -#: notebook/static/notebook/js/actions.js:799 -msgid "trust notebook" -msgstr "信任笔记本" - -#: notebook/static/notebook/js/actions.js:800 -msgid "Trust the current notebook" -msgstr "信任当前笔记本" - -#: notebook/static/notebook/js/actions.js:806 -msgid "rename notebook" -msgstr "重命名笔记本" - -#: notebook/static/notebook/js/actions.js:807 -msgid "Rename the current notebook" -msgstr "重命名当前笔记本" - -#: notebook/static/notebook/js/actions.js:813 -msgid "toggle all cells output collapsed" -msgstr "切换折叠所有单元格的输出" - -#: notebook/static/notebook/js/actions.js:814 -msgid "Toggle the hidden state of all output areas" -msgstr "切换所有输出区域的隐藏状态" - -#: notebook/static/notebook/js/actions.js:820 -msgid "toggle all cells output scrolled" -msgstr "切换所有单元格输出的滚动状态" - -#: notebook/static/notebook/js/actions.js:821 -msgid "Toggle the scrolling state of all output areas" -msgstr "切换所有输出区域的滚动状态" - -#: notebook/static/notebook/js/actions.js:828 -msgid "clear all cells output" -msgstr "清空所有单元格输出" - -#: notebook/static/notebook/js/actions.js:829 -msgid "Clear the content of all the outputs" -msgstr "清空所有的输出内容" - -#: notebook/static/notebook/js/actions.js:835 -msgid "save notebook" -msgstr "保存笔记本" - -#: notebook/static/notebook/js/actions.js:836 -msgid "Save and Checkpoint" -msgstr "保存并建立检查点" - -#: notebook/static/notebook/js/cell.js:79 -msgid "Warning: accessing Cell.cm_config directly is deprecated." -msgstr "警告: 直接访问 Cell.cm_config 已经被弃用了。" - -#: notebook/static/notebook/js/cell.js:763 -#, python-format -msgid "Unrecognized cell type: %s" -msgstr "未知的单元格类型: %s" - -#: notebook/static/notebook/js/cell.js:777 -msgid "Unrecognized cell type" -msgstr "未知的单元格类型" - -#: notebook/static/notebook/js/celltoolbar.js:296 -#, python-format -msgid "Error in cell toolbar callback %s" -msgstr "工具栏调用 %s 出现错误" - -#: notebook/static/notebook/js/clipboard.js:53 -#, python-format -msgid "Clipboard types: %s" -msgstr "剪贴板类型: %s" - -#: notebook/static/notebook/js/clipboard.js:96 -msgid "Dialog for paste from system clipboard" -msgstr "从系统剪切板粘贴" - -#: notebook/static/notebook/js/clipboard.js:109 -msgid "Ctrl-V" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:111 -msgid "Cmd-V" -msgstr "" - -#: notebook/static/notebook/js/clipboard.js:113 -#, python-format -msgid "Press %s again to paste" -msgstr "再按一次 %s 来粘贴" - -#: notebook/static/notebook/js/clipboard.js:116 -msgid "Why is this needed? " -msgstr "为什么需要它?" - -#: notebook/static/notebook/js/clipboard.js:118 -msgid "We can't get paste events in this browser without a text box. " -msgstr "在浏览器里没有文本框我们不能粘贴. " - -#: notebook/static/notebook/js/clipboard.js:119 -msgid "There's an invisible text box focused in this dialog." -msgstr "在这个对话框中有一个不可见的文本框." - -#: notebook/static/notebook/js/clipboard.js:125 -#, python-format -msgid "%s to paste" -msgstr "%s 来粘贴" - -#: notebook/static/notebook/js/codecell.js:310 -msgid "Can't execute cell since kernel is not set." -msgstr "当前不能执行单元格代码,因为内核还没有准备好。" - -#: notebook/static/notebook/js/codecell.js:481 -msgid "In" -msgstr "" - -#: notebook/static/notebook/js/kernelselector.js:269 -#, python-format -msgid "Could not find a kernel matching %s. Please select a kernel:" -msgstr "找不到匹配 %s 的内核。请选择一个内核:" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Continue Without Kernel" -msgstr "无内核继续运行" - -#: notebook/static/notebook/js/kernelselector.js:278 -msgid "Set Kernel" -msgstr "设置内核" - -#: notebook/static/notebook/js/kernelselector.js:281 -msgid "Kernel not found" -msgstr "找不到内核" - -#: notebook/static/notebook/js/kernelselector.js:319 -#: notebook/static/tree/js/newnotebook.js:99 -msgid "Creating Notebook Failed" -msgstr "创建笔记本失败" - -#: notebook/static/notebook/js/kernelselector.js:320 -#: notebook/static/tree/js/notebooklist.js:1362 -#, python-format -msgid "The error was: %s" -msgstr "错误: %s" - -#: notebook/static/notebook/js/maintoolbar.js:54 -msgid "Run" -msgstr "运行" - -#: notebook/static/notebook/js/maintoolbar.js:76 -msgid "Code" -msgstr "代码" - -#: notebook/static/notebook/js/maintoolbar.js:77 -msgid "Markdown" -msgstr "Markdown" - -#: notebook/static/notebook/js/maintoolbar.js:78 -msgid "Raw NBConvert" -msgstr "原生 NBConvert" - -#: notebook/static/notebook/js/maintoolbar.js:79 -msgid "Heading" -msgstr "标题" - -#: notebook/static/notebook/js/maintoolbar.js:115 -msgid "unrecognized cell type:" -msgstr "未识别的单元格类型:" - -#: notebook/static/notebook/js/mathjaxutils.js:45 -#, python-format -msgid "Failed to retrieve MathJax from '%s'" -msgstr "未能从 '%s' 中检索 MathJax" - -#: notebook/static/notebook/js/mathjaxutils.js:47 -msgid "Math/LaTeX rendering will be disabled." -msgstr "Math/LaTeX 渲染将被禁用。" - -#: notebook/static/notebook/js/menubar.js:220 -msgid "Trusted Notebook" -msgstr "可信的笔记本" - -#: notebook/static/notebook/js/menubar.js:226 -msgid "Trust Notebook" -msgstr "信任笔记本" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:16 -#: notebook/static/notebook/js/menubar.js:383 -msgid "None" -msgstr "无" - -#: notebook/static/notebook/js/menubar.js:406 -msgid "No checkpoints" -msgstr "没有检查点" - -#: notebook/static/notebook/js/menubar.js:465 -msgid "Opens in a new window" -msgstr "在新窗口打开" - -#: notebook/static/notebook/js/notebook.js:441 -msgid "Autosave in progress, latest changes may be lost." -msgstr "自动保存进行中,最新的改变可能会丢失。" - -#: notebook/static/notebook/js/notebook.js:443 -msgid "Unsaved changes will be lost." -msgstr "未保存的修改将会丢失。" - -#: notebook/static/notebook/js/notebook.js:448 -msgid "The Kernel is busy, outputs may be lost." -msgstr "内核正忙,输出也许会丢失。" - -#: notebook/static/notebook/js/notebook.js:471 -msgid "This notebook is version %1$s, but we only fully support up to %2$s." -msgstr "该笔记本使用了版本 %1$s,但是我们只支持到 %2$s." - -#: notebook/static/notebook/js/notebook.js:473 -msgid "You can still work with this notebook, but cell and output types introduced in later notebook versions will not be available." -msgstr "您仍然可以使用该笔记本,但是在新版本中引入的单元和输出类型将不可用。" - -#: notebook/static/notebook/js/notebook.js:480 -msgid "Restart and Run All Cells" -msgstr "重启并运行所有代码块" - -#: notebook/static/notebook/js/notebook.js:481 -msgid "Restart and Clear All Outputs" -msgstr "重启并清空所有输出" - -#: notebook/static/notebook/js/notebook.js:482 -msgid "Restart" -msgstr "重启" - -#: notebook/static/notebook/js/notebook.js:483 -msgid "Continue Running" -msgstr "继续运行" - -#: notebook/static/notebook/js/notebook.js:484 -msgid "Reload" -msgstr "重载" - -#: notebook/static/notebook/js/notebook.js:486 -msgid "Overwrite" -msgstr "重写" - -#: notebook/static/notebook/js/notebook.js:487 -msgid "Trust" -msgstr "信任" - -#: notebook/static/notebook/js/notebook.js:488 -msgid "Revert" -msgstr "恢复" - -#: notebook/static/notebook/js/notebook.js:493 -msgid "Newer Notebook" -msgstr "新笔记本" - -#: notebook/static/notebook/js/notebook.js:1558 -msgid "Use markdown headings" -msgstr "使用 Markdown 标题" - -#: notebook/static/notebook/js/notebook.js:1560 -msgid "Jupyter no longer uses special heading cells. Instead, write your headings in Markdown cells using # characters:" -msgstr "Jupyter 不再使用特殊的标题单元格。请在 Markdown 单元格中使用 # 字符来写标题:" - -#: notebook/static/notebook/js/notebook.js:1563 -msgid "## This is a level 2 heading" -msgstr "## 这是一个二级标题" - -#: notebook/static/notebook/js/notebook.js:2261 -msgid "Restart kernel and re-run the whole notebook?" -msgstr "重新启动内核并重新运行整个笔记本?" - -#: notebook/static/notebook/js/notebook.js:2263 -msgid "Are you sure you want to restart the current kernel and re-execute the whole notebook? All variables and outputs will be lost." -msgstr "您确定要重新启动当前的内核并重新执行整个笔记本吗?所有的变量和输出都将丢失。" - -#: notebook/static/notebook/js/notebook.js:2288 -msgid "Restart kernel and clear all output?" -msgstr "重启内核并且清空输出?" - -#: notebook/static/notebook/js/notebook.js:2290 -msgid "Do you want to restart the current kernel and clear all output? All variables and outputs will be lost." -msgstr "您是否希望重新启动当前的内核并清除所有输出?所有的变量和输出都将丢失。" - -#: notebook/static/notebook/js/notebook.js:2335 -msgid "Restart kernel?" -msgstr "重启内核?" - -#: notebook/static/notebook/js/notebook.js:2337 -msgid "Do you want to restart the current kernel? All variables will be lost." -msgstr "如果重启内核,所有变量都会丢失。是否重启?" - -#: notebook/static/notebook/js/notebook.js:2320 -msgid "Shutdown kernel?" -msgstr "关闭内核?" - -#: notebook/static/notebook/js/notebook.js:2322 -msgid "Do you want to shutdown the current kernel? All variables will be lost." -msgstr "如果关闭内核,所有变量都会丢失。是否关闭?" - -#: notebook/static/notebook/js/notebook.js:2750 -msgid "Notebook changed" -msgstr "笔记本改变了" - -#: notebook/static/notebook/js/notebook.js:2751 -msgid "The notebook file has changed on disk since the last time we opened or saved it. Do you want to overwrite the file on disk with the version open here, or load the version on disk (reload the page)?" -msgstr "自从上次我们打开或保存它以来,笔记本文件已经在磁盘上发生了变化。您希望用这里打开的版本覆盖磁盘上的版本,还是加载磁盘上的版本(刷新页面)?" - -#: notebook/static/notebook/js/notebook.js:2798 -#: notebook/static/notebook/js/notebook.js:3020 -msgid "Notebook validation failed" -msgstr "Notebook 校验失败" - -#: notebook/static/notebook/js/notebook.js:2801 -msgid "The save operation succeeded, but the notebook does not appear to be valid. The validation error was:" -msgstr "保存操作成功了,但是这个笔记本看起来并不有效。校验错误:" - -#: notebook/static/notebook/js/notebook.js:2852 -msgid "A trusted Jupyter notebook may execute hidden malicious code when you open it. Selecting trust will immediately reload this notebook in a trusted state. For more information, see the Jupyter security documentation: " -msgstr "当你打开一个可信任的 Jupyter 笔记本时,它可能会执行隐藏的恶意代码。选择信任将立即在一个可信的状态中重新加载这个笔记本。要了解更多信息,请参阅 Jupyter 安全文档:" - -#: notebook/static/notebook/js/notebook.js:2856 -msgid "here" -msgstr "这里" - -#: notebook/static/notebook/js/notebook.js:2864 -msgid "Trust this notebook?" -msgstr "信任这个笔记本?" - -#: notebook/static/notebook/js/notebook.js:3011 -msgid "Notebook failed to load" -msgstr "笔记本加载失败" - -#: notebook/static/notebook/js/notebook.js:3013 -msgid "The error was: " -msgstr "错误: " - -#: notebook/static/notebook/js/notebook.js:3017 -msgid "See the error console for details." -msgstr "有关详细信息,请参阅错误控制台。" - -#: notebook/static/notebook/js/notebook.js:3025 -msgid "The notebook also failed validation:" -msgstr "这个笔记本校验也失败了:" - -#: notebook/static/notebook/js/notebook.js:3027 -msgid "An invalid notebook may not function properly. The validation error was:" -msgstr "无效的笔记本可能无法正常运行。校验错误:" - -#: notebook/static/notebook/js/notebook.js:3066 -#, python-format -msgid "This notebook has been converted from an older notebook format to the current notebook format v(%s)." -msgstr "本笔记本已从较旧的笔记本格式转换为当前的笔记本格式 v(%s)。" - -#: notebook/static/notebook/js/notebook.js:3068 -#, python-format -msgid "This notebook has been converted from a newer notebook format to the current notebook format v(%s)." -msgstr "这个笔记本已经从一种新的笔记本格式转换为当前的笔记本格式 v(%s)。" - -#: notebook/static/notebook/js/notebook.js:3076 -msgid "The next time you save this notebook, the current notebook format will be used." -msgstr "下次你保存这个笔记本时,当前的笔记本格式将会被使用。" - -#: notebook/static/notebook/js/notebook.js:3081 -msgid "Older versions of Jupyter may not be able to read the new format." -msgstr "旧版本的 Jupyter 可能无法读取新格式。" - -#: notebook/static/notebook/js/notebook.js:3083 -msgid "Some features of the original notebook may not be available." -msgstr "原笔记本的一些特性可能无法使用。" - -#: notebook/static/notebook/js/notebook.js:3086 -msgid "To preserve the original version, close the notebook without saving it." -msgstr "为了保存原始版本,关闭笔记本而不保存它。" - -#: notebook/static/notebook/js/notebook.js:3091 -msgid "Notebook converted" -msgstr "已转换笔记本" - -#: notebook/static/notebook/js/notebook.js:3113 -msgid "(No name)" -msgstr "(没有名字)" - -#: notebook/static/notebook/js/notebook.js:3161 -#, python-format -msgid "An unknown error occurred while loading this notebook. This version can load notebook formats %s or earlier. See the server log for details." -msgstr "加载本笔记本时出现了一个未知的错误。这个版本可以加载 %s 或更早的笔记本。有关详细信息,请参阅服务器日志。" - -#: notebook/static/notebook/js/notebook.js:3172 -msgid "Error loading notebook" -msgstr "加载笔记本出错" - -#: notebook/static/notebook/js/notebook.js:3273 -msgid "Are you sure you want to revert the notebook to the latest checkpoint?" -msgstr "确定将笔记本恢复至最近的检查点?" - -#: notebook/static/notebook/js/notebook.js:3276 -msgid "This cannot be undone." -msgstr "该操作不能被还原。" - -#: notebook/static/notebook/js/notebook.js:3279 -msgid "The checkpoint was last updated at:" -msgstr "笔记本的最新检查点更新于:" - -#: notebook/static/notebook/js/notebook.js:3290 -msgid "Revert notebook to checkpoint" -msgstr "恢复笔记本至检查点" - -#: notebook/static/notebook/js/notificationarea.js:76 -#: notebook/static/notebook/js/tour.js:61 -#: notebook/static/notebook/js/tour.js:67 -msgid "Edit Mode" -msgstr "编辑模式" - -#: notebook/static/notebook/js/notificationarea.js:83 -#: notebook/static/notebook/js/notificationarea.js:87 -#: notebook/static/notebook/js/tour.js:54 -msgid "Command Mode" -msgstr "命令模式" - -#: notebook/static/notebook/js/notificationarea.js:94 -msgid "Kernel Created" -msgstr "内核已创建" - -#: notebook/static/notebook/js/notificationarea.js:98 -msgid "Connecting to kernel" -msgstr "正在连接内核" - -#: notebook/static/notebook/js/notificationarea.js:102 -msgid "Not Connected" -msgstr "未连接" - -#: notebook/static/notebook/js/notificationarea.js:105 -msgid "click to reconnect" -msgstr "点击重连" - -#: notebook/static/notebook/js/notificationarea.js:114 -msgid "Restarting kernel" -msgstr "重启内核" - -#: notebook/static/notebook/js/notificationarea.js:128 -msgid "Kernel Restarting" -msgstr "内核正在重启" - -#: notebook/static/notebook/js/notificationarea.js:129 -msgid "The kernel appears to have died. It will restart automatically." -msgstr "内核似乎挂掉了,它很快将自动重启。" - -#: notebook/static/notebook/js/notificationarea.js:139 -#: notebook/static/notebook/js/notificationarea.js:197 -#: notebook/static/notebook/js/notificationarea.js:217 -msgid "Dead kernel" -msgstr "挂掉的内核" - -#: notebook/static/notebook/js/notificationarea.js:140 -#: notebook/static/notebook/js/notificationarea.js:218 -#: notebook/static/notebook/js/notificationarea.js:265 -msgid "Kernel Dead" -msgstr "内核挂掉" - -#: notebook/static/notebook/js/notificationarea.js:144 -msgid "Interrupting kernel" -msgstr "正在中断内核" - -#: notebook/static/notebook/js/notificationarea.js:150 -msgid "No Connection to Kernel" -msgstr "没有连接到内核" - -#: notebook/static/notebook/js/notificationarea.js:160 -msgid "A connection to the notebook server could not be established. The notebook will continue trying to reconnect. Check your network connection or notebook server configuration." -msgstr "无法建立到笔记本服务器的连接。 我们会继续尝试重连。请检查网络连接还有服务配置。" - -#: notebook/static/notebook/js/notificationarea.js:165 -msgid "Connection failed" -msgstr "连接失败" - -#: notebook/static/notebook/js/notificationarea.js:178 -msgid "No kernel" -msgstr "没有内核" - -#: notebook/static/notebook/js/notificationarea.js:179 -msgid "Kernel is not running" -msgstr "内核没有运行" - -#: notebook/static/notebook/js/notificationarea.js:186 -msgid "Don't Restart" -msgstr "不要重启" - -#: notebook/static/notebook/js/notificationarea.js:186 -msgid "Try Restarting Now" -msgstr "现在尝试重启" - -#: notebook/static/notebook/js/notificationarea.js:190 -msgid "The kernel has died, and the automatic restart has failed. It is possible the kernel cannot be restarted. If you are not able to restart the kernel, you will still be able to save the notebook, but running code will no longer work until the notebook is reopened." -msgstr "内核已经死亡,自动重启也失败了。可能是内核不能重新启动。如果您不能重新启动内核,您仍然能够保存笔记本,但笔记本要重新打开才能运行代码。" - -#: notebook/static/notebook/js/notificationarea.js:224 -msgid "No Kernel" -msgstr "没有内核" - -#: notebook/static/notebook/js/notificationarea.js:251 -msgid "Failed to start the kernel" -msgstr "启动内核失败" - -#: notebook/static/notebook/js/notificationarea.js:271 -#: notebook/static/notebook/js/notificationarea.js:291 -#: notebook/static/notebook/js/notificationarea.js:305 -msgid "Kernel Busy" -msgstr "内核正忙" - -#: notebook/static/notebook/js/notificationarea.js:272 -msgid "Kernel starting, please wait..." -msgstr "内核正在启动,请等待..." - -#: notebook/static/notebook/js/notificationarea.js:278 -#: notebook/static/notebook/js/notificationarea.js:285 -msgid "Kernel Idle" -msgstr "内核空闲" - -#: notebook/static/notebook/js/notificationarea.js:279 -msgid "Kernel ready" -msgstr "内核就绪" - -#: notebook/static/notebook/js/notificationarea.js:296 -msgid "Using kernel: " -msgstr "使用内核:" - -#: notebook/static/notebook/js/notificationarea.js:297 -msgid "Only candidate for language: %1$s was %2$s." -msgstr "只支持语言: %1$s - %2$s." - -#: notebook/static/notebook/js/notificationarea.js:318 -msgid "Loading notebook" -msgstr "加载笔记本" - -#: notebook/static/notebook/js/notificationarea.js:321 -msgid "Notebook loaded" -msgstr "笔记本已加载" - -#: notebook/static/notebook/js/notificationarea.js:324 -msgid "Saving notebook" -msgstr "保存笔记本" - -#: notebook/static/notebook/js/notificationarea.js:327 -msgid "Notebook saved" -msgstr "笔记本已保存" - -#: notebook/static/notebook/js/notificationarea.js:330 -msgid "Notebook save failed" -msgstr "笔记本保存失败" - -#: notebook/static/notebook/js/notificationarea.js:333 -msgid "Notebook copy failed" -msgstr "笔记本复制失败" - -#: notebook/static/notebook/js/notificationarea.js:338 -msgid "Checkpoint created" -msgstr "检查点已创建" - -#: notebook/static/notebook/js/notificationarea.js:346 -msgid "Checkpoint failed" -msgstr "检查点创建失败" - -#: notebook/static/notebook/js/notificationarea.js:349 -msgid "Checkpoint deleted" -msgstr "检查点已删除" - -#: notebook/static/notebook/js/notificationarea.js:352 -msgid "Checkpoint delete failed" -msgstr "检查点删除失败" - -#: notebook/static/notebook/js/notificationarea.js:355 -msgid "Restoring to checkpoint..." -msgstr "正在恢复至检查点..." - -#: notebook/static/notebook/js/notificationarea.js:358 -msgid "Checkpoint restore failed" -msgstr "检查点恢复失败" - -#: notebook/static/notebook/js/notificationarea.js:363 -msgid "Autosave disabled" -msgstr "自动保存失败" - -#: notebook/static/notebook/js/notificationarea.js:366 -#, python-format -msgid "Saving every %d sec." -msgstr "每隔 %s 秒保存一次。" - -#: notebook/static/notebook/js/notificationarea.js:382 -msgid "Trusted" -msgstr "可信" - -#: notebook/static/notebook/js/notificationarea.js:384 -msgid "Not Trusted" -msgstr "不可信" - -#: notebook/static/notebook/js/outputarea.js:85 -msgid "click to expand output" -msgstr "点击展开输出" - -#: notebook/static/notebook/js/outputarea.js:89 -msgid "click to expand output; double click to hide output" -msgstr "点击展开输出;双击隐藏输出" - -#: notebook/static/notebook/js/outputarea.js:177 -msgid "click to unscroll output; double click to hide" -msgstr "单击取消滚动输出;双击隐藏" - -#: notebook/static/notebook/js/outputarea.js:184 -msgid "click to scroll output; double click to hide" -msgstr "点击滚动输出;双击隐藏" - -#: notebook/static/notebook/js/outputarea.js:434 -msgid "Javascript error adding output!" -msgstr "添加输出时 Javascript 出错了!" - -#: notebook/static/notebook/js/outputarea.js:439 -msgid "See your browser Javascript console for more details." -msgstr "更多细节请参见您的浏览器 Javascript 控制台。" - -#: notebook/static/notebook/js/outputarea.js:480 -#, python-format -msgid "Out[%d]:" -msgstr "" - -#: notebook/static/notebook/js/outputarea.js:589 -#, python-format -msgid "Unrecognized output: %s" -msgstr "未识别的输出: %s" - -#: notebook/static/notebook/js/pager.js:36 -msgid "Open the pager in an external window" -msgstr "在外部窗口打开分页器" - -#: notebook/static/notebook/js/pager.js:45 -msgid "Close the pager" -msgstr "关闭分页器" - -#: notebook/static/notebook/js/pager.js:148 -msgid "Jupyter Pager" -msgstr "Jupyter 分页器" - -#: notebook/static/notebook/js/quickhelp.js:39 -#: notebook/static/notebook/js/quickhelp.js:54 -#: notebook/static/notebook/js/quickhelp.js:55 -msgid "go to cell start" -msgstr "跳到单元格起始处" - -#: notebook/static/notebook/js/quickhelp.js:40 -#: notebook/static/notebook/js/quickhelp.js:56 -#: notebook/static/notebook/js/quickhelp.js:57 -msgid "go to cell end" -msgstr "跳到单元格最后" - -#: notebook/static/notebook/js/quickhelp.js:41 -#: notebook/static/notebook/js/quickhelp.js:58 -msgid "go one word left" -msgstr "往左跳一个单词" - -#: notebook/static/notebook/js/quickhelp.js:42 -#: notebook/static/notebook/js/quickhelp.js:59 -msgid "go one word right" -msgstr "往右跳一个单词" - -#: notebook/static/notebook/js/quickhelp.js:43 -#: notebook/static/notebook/js/quickhelp.js:60 -msgid "delete word before" -msgstr "删除前面的单词" - -#: notebook/static/notebook/js/quickhelp.js:44 -#: notebook/static/notebook/js/quickhelp.js:61 -msgid "delete word after" -msgstr "删除后面的单词" - -#: notebook/static/notebook/js/quickhelp.js:45 -#: notebook/static/notebook/js/quickhelp.js:62 -msgid "redo" -msgstr "重做" - -#: notebook/static/notebook/js/quickhelp.js:46 -#: notebook/static/notebook/js/quickhelp.js:63 -msgid "redo selection" -msgstr "重新选择" - -#: notebook/static/notebook/js/quickhelp.js:47 -msgid "emacs-style line kill" -msgstr "Emacs 风格的 Line Kill" - -#: notebook/static/notebook/js/quickhelp.js:48 -msgid "delete line left of cursor" -msgstr "删除光标左边一行" - -#: notebook/static/notebook/js/quickhelp.js:49 -msgid "delete line right of cursor" -msgstr "删除光标右边一行" - -#: notebook/static/notebook/js/quickhelp.js:68 -msgid "code completion or indent" -msgstr "代码补全或缩进" - -#: notebook/static/notebook/js/quickhelp.js:69 -msgid "tooltip" -msgstr "工具提示" - -#: notebook/static/notebook/js/quickhelp.js:70 -msgid "indent" -msgstr "缩进" - -#: notebook/static/notebook/js/quickhelp.js:71 -msgid "dedent" -msgstr "取消缩进" - -#: notebook/static/notebook/js/quickhelp.js:72 -msgid "select all" -msgstr "全选" - -#: notebook/static/notebook/js/quickhelp.js:73 -msgid "undo" -msgstr "撤销" - -#: notebook/static/notebook/js/quickhelp.js:74 -msgid "comment" -msgstr "注释" - -#: notebook/static/notebook/js/quickhelp.js:75 -msgid "delete whole line" -msgstr "删除整行" - -#: notebook/static/notebook/js/quickhelp.js:76 -msgid "undo selection" -msgstr "撤销选择" - -#: notebook/static/notebook/js/quickhelp.js:77 -msgid "toggle overwrite flag" -msgstr "切换重写标志" - -#: notebook/static/notebook/js/quickhelp.js:111 -#: notebook/static/notebook/js/quickhelp.js:252 -msgid "Shift" -msgstr "Shift" - -#: notebook/static/notebook/js/quickhelp.js:112 -msgid "Alt" -msgstr "Alt" - -#: notebook/static/notebook/js/quickhelp.js:113 -msgid "Up" -msgstr "上" - -#: notebook/static/notebook/js/quickhelp.js:114 -msgid "Down" -msgstr "下" - -#: notebook/static/notebook/js/quickhelp.js:115 -msgid "Left" -msgstr "左" - -#: notebook/static/notebook/js/quickhelp.js:116 -msgid "Right" -msgstr "右" - -#: notebook/static/notebook/js/quickhelp.js:117 -#: notebook/static/notebook/js/quickhelp.js:255 -msgid "Tab" -msgstr "Tab" - -#: notebook/static/notebook/js/quickhelp.js:118 -msgid "Caps Lock" -msgstr "大写锁定" - -#: notebook/static/notebook/js/quickhelp.js:119 -#: notebook/static/notebook/js/quickhelp.js:278 -msgid "Esc" -msgstr "Esc" - -#: notebook/static/notebook/js/quickhelp.js:120 -msgid "Ctrl" -msgstr "Ctrl" - -#: notebook/static/notebook/js/quickhelp.js:121 -#: notebook/static/notebook/js/quickhelp.js:299 -msgid "Enter" -msgstr "Enter" - -#: notebook/static/notebook/js/quickhelp.js:122 -msgid "Page Up" -msgstr "上一页" - -#: notebook/static/notebook/js/quickhelp.js:123 -#: notebook/static/notebook/js/quickhelp.js:139 -msgid "Page Down" -msgstr "下一页" - -#: notebook/static/notebook/js/quickhelp.js:124 -msgid "Home" -msgstr "Home" - -#: notebook/static/notebook/js/quickhelp.js:125 -msgid "End" -msgstr "End" - -#: notebook/static/notebook/js/quickhelp.js:126 -#: notebook/static/notebook/js/quickhelp.js:254 -msgid "Space" -msgstr "空格" - -#: notebook/static/notebook/js/quickhelp.js:127 -msgid "Backspace" -msgstr "退格" - -#: notebook/static/notebook/js/quickhelp.js:128 -msgid "Minus" -msgstr "" - -#: notebook/static/notebook/js/quickhelp.js:139 -msgid "PageUp" -msgstr "上一页" - -#: notebook/static/notebook/js/quickhelp.js:206 -msgid "The Jupyter Notebook has two different keyboard input modes." -msgstr "Jupyter 笔记本有两种不同的键盘输入模式。" - -#: notebook/static/notebook/js/quickhelp.js:208 -msgid "Edit mode allows you to type code or text into a cell and is indicated by a green cell border." -msgstr "编辑模式允许您将代码或文本输入到一个单元格中,并通过一个绿色边框的单元格来表示" - -#: notebook/static/notebook/js/quickhelp.js:210 -msgid "Command mode binds the keyboard to notebook level commands and is indicated by a grey cell border with a blue left margin." -msgstr "命令模式将键盘与笔记本级命令绑定在一起,并通过一个灰框、左边距蓝色的单元格显示。" - -#: notebook/static/notebook/js/quickhelp.js:231 -#: notebook/static/notebook/js/tooltip.js:58 -#: notebook/static/notebook/js/tooltip.js:69 -msgid "Close" -msgstr "关闭" - -#: notebook/static/notebook/js/quickhelp.js:234 -msgid "Keyboard shortcuts" -msgstr "键盘快捷键" - -#: notebook/static/notebook/js/quickhelp.js:249 -msgid "Command" -msgstr "命令" - -#: notebook/static/notebook/js/quickhelp.js:250 -msgid "Control" -msgstr "控制" - -#: notebook/static/notebook/js/quickhelp.js:251 -msgid "Option" -msgstr "选项" - -#: notebook/static/notebook/js/quickhelp.js:253 -msgid "Return" -msgstr "返回" - -#: notebook/static/notebook/js/quickhelp.js:279 -#, python-format -msgid "Command Mode (press %s to enable)" -msgstr "命令行模式(按 %s 生效)" - -#: notebook/static/notebook/js/quickhelp.js:281 -msgid "Edit Shortcuts" -msgstr "编辑快捷键" - -#: notebook/static/notebook/js/quickhelp.js:284 -msgid "edit command-mode keyboard shortcuts" -msgstr "编辑命令模式键盘快捷键" - -#: notebook/static/notebook/js/quickhelp.js:301 -#, python-format -msgid "Edit Mode (press %s to enable)" -msgstr "编辑模式(按 %s 生效)" - -#: notebook/static/notebook/js/savewidget.js:49 -msgid "Autosave Failed!" -msgstr "自动保存失败!" - -#: notebook/static/notebook/js/savewidget.js:71 -#: notebook/static/tree/js/notebooklist.js:850 -#: notebook/static/tree/js/notebooklist.js:863 -msgid "Rename" -msgstr "重命名" - -#: notebook/static/notebook/js/savewidget.js:78 -#: notebook/static/tree/js/notebooklist.js:841 -msgid "Enter a new notebook name:" -msgstr "请输入新的笔记本名称:" - -#: notebook/static/notebook/js/savewidget.js:86 -msgid "Rename Notebook" -msgstr "重命名笔记本" - -#: notebook/static/notebook/js/savewidget.js:98 -msgid "Invalid notebook name. Notebook names must have 1 or more characters and can contain any characters except :/\\. Please enter a new notebook name:" -msgstr "无效的笔记本名称。笔记本名称不能为空,并且不能包含\":/.\"。请输入一个新的笔记本名称:" - -#: notebook/static/notebook/js/savewidget.js:103 -msgid "Renaming..." -msgstr "正在重命名…" - -#: notebook/static/notebook/js/savewidget.js:109 -msgid "Unknown error" -msgstr "未知错误" - -#: notebook/static/notebook/js/savewidget.js:178 -msgid "no checkpoint" -msgstr "没有检查点" - -#: notebook/static/notebook/js/savewidget.js:193 -#, python-format -msgid "Last Checkpoint: %s" -msgstr "最新检查点: %s " - -#: notebook/static/notebook/js/savewidget.js:217 -msgid "(unsaved changes)" -msgstr "(更改未保存)" - -#: notebook/static/notebook/js/savewidget.js:219 -msgid "(autosaved)" -msgstr "(已自动保存)" - -#: notebook/static/notebook/js/searchandreplace.js:71 -#, python-format -msgid "Warning: too many matches (%d). Some changes might not be shown or applied." -msgstr "警告:太多的匹配(%d)。有些更改可能不会被显示或应用." - -#: notebook/static/notebook/js/searchandreplace.js:74 -#, python-format -msgid "%d match" -msgid_plural "%d matches" -msgstr[0] "%d 匹配" -msgstr[1] "%d 匹配" - -#: notebook/static/notebook/js/searchandreplace.js:141 -msgid "More than 100 matches, aborting" -msgstr "超过 100 个匹配, 中止" - -#: notebook/static/notebook/js/searchandreplace.js:161 -msgid "Use regex (JavaScript regex syntax)" -msgstr "使用正则表达式(JavaScript 正则表达式语法)" - -#: notebook/static/notebook/js/searchandreplace.js:169 -msgid "Replace in selected cells" -msgstr "在选中单元格中替换" - -#: notebook/static/notebook/js/searchandreplace.js:176 -msgid "Match case" -msgstr "匹配大小写" - -#: notebook/static/notebook/js/searchandreplace.js:182 -msgid "Find" -msgstr "查找" - -#: notebook/static/notebook/js/searchandreplace.js:198 -msgid "Replace" -msgstr "替换" - -#: notebook/static/notebook/js/searchandreplace.js:244 -msgid "No matches, invalid or empty regular expression" -msgstr "无匹配,表达式无效或表达式为空" - -#: notebook/static/notebook/js/searchandreplace.js:348 -msgid "Replace All" -msgstr "全部替换" - -#: notebook/static/notebook/js/searchandreplace.js:352 -msgid "Find and Replace" -msgstr "查找并且替换" - -#: notebook/static/notebook/js/searchandreplace.js:377 -#: notebook/static/notebook/js/searchandreplace.js:378 -msgid "find and replace" -msgstr "查找并且替换" - -#: notebook/static/notebook/js/textcell.js:559 -msgid "Write raw LaTeX or other formats here, for use with nbconvert. It will not be rendered in the notebook. When passing through nbconvert, a Raw Cell's content is added to the output unmodified." -msgstr "在这里直接写 LaTeX 或者其它格式的文本来配合 nbconvert。笔记本不会渲染它。传给 nbconvert 时,原始单元格的内容会被完好地加进输出。" - -#: notebook/static/notebook/js/tooltip.js:41 -msgid "Grow the tooltip vertically (press shift-tab twice)" -msgstr "纵向展开工具提示(按两次 Shift+Tab)" - -#: notebook/static/notebook/js/tooltip.js:48 -msgid "show the current docstring in pager (press shift-tab 4 times)" -msgstr "在分页器中显示当前的文档字符串(按四次 Shift+Tab)" - -#: notebook/static/notebook/js/tooltip.js:49 -msgid "Open in Pager" -msgstr "在分页器中打开" - -#: notebook/static/notebook/js/tooltip.js:68 -msgid "Tooltip will linger for 10 seconds while you type" -msgstr "当您键入时,工具提示会停留十秒" - -#: notebook/static/notebook/js/tour.js:27 -msgid "Welcome to the Notebook Tour" -msgstr "欢迎来到 Notebook 导览" - -#: notebook/static/notebook/js/tour.js:30 -msgid "You can use the left and right arrow keys to go backwards and forwards." -msgstr "你可以使用左右箭头键来前后移动" - -#: notebook/static/notebook/js/tour.js:33 -msgid "Filename" -msgstr "文件名" - -#: notebook/static/notebook/js/tour.js:35 -msgid "Click here to change the filename for this notebook." -msgstr "点击这里修改笔记本的文件名" - -#: notebook/static/notebook/js/tour.js:39 -msgid "Notebook Menubar" -msgstr "笔记本菜单栏" - -#: notebook/static/notebook/js/tour.js:40 -msgid "The menubar has menus for actions on the notebook, its cells, and the kernel it communicates with." -msgstr "菜单栏上的菜单可以用来操作笔记本、单元格和与笔记本通信的内核。" - -#: notebook/static/notebook/js/tour.js:44 -msgid "Notebook Toolbar" -msgstr "笔记本工具栏" - -#: notebook/static/notebook/js/tour.js:45 -msgid "The toolbar has buttons for the most common actions. Hover your mouse over each button for more information." -msgstr "工具栏有最常见操作的按钮。将鼠标悬停在每个按钮上以获得更多信息。" - -#: notebook/static/notebook/js/tour.js:48 -msgid "Mode Indicator" -msgstr "模式指示器" - -#: notebook/static/notebook/js/tour.js:50 -msgid "The Notebook has two modes: Edit Mode and Command Mode. In this area, an indicator can appear to tell you which mode you are in." -msgstr "笔记本有两种模式:编辑模式和命令模式。在这个区域,一个指示器可以显示你在哪个模式。" - -#: notebook/static/notebook/js/tour.js:58 -msgid "Right now you are in Command Mode, and many keyboard shortcuts are available. In this mode, no icon is displayed in the indicator area." -msgstr "现在你处于命令模式,许多快捷键都可以使用。在该模式下,指示区域中没有显示图标。" - -#: notebook/static/notebook/js/tour.js:64 -msgid "Pressing Enter or clicking in the input text area of the cell switches to Edit Mode." -msgstr "按下Enter或者点击输入文本区域来切换到编辑模式. " - -#: notebook/static/notebook/js/tour.js:70 -msgid "Notice that the border around the currently active cell changed color. Typing will insert text into the currently active cell." -msgstr "您会发现当前活动单元格周围的边框改变了颜色。键入将在当前活动单元格中插入文本." - -#: notebook/static/notebook/js/tour.js:73 -msgid "Back to Command Mode" -msgstr "回到命令模式" - -#: notebook/static/notebook/js/tour.js:76 -msgid "Pressing Esc or clicking outside of the input text area takes you back to Command Mode." -msgstr "按下Esc或者点击输入框外面来返回到命令模式。" - -#: notebook/static/notebook/js/tour.js:79 -msgid "Keyboard Shortcuts" -msgstr "键盘快捷键" - -#: notebook/static/notebook/js/tour.js:91 -msgid "You can click here to get a list of all of the keyboard shortcuts." -msgstr "点击这里获得所有键盘快捷键" - -#: notebook/static/notebook/js/tour.js:94 -#: notebook/static/notebook/js/tour.js:100 -msgid "Kernel Indicator" -msgstr "内核指示器" - -#: notebook/static/notebook/js/tour.js:97 -msgid "This is the Kernel indicator. It looks like this when the Kernel is idle." -msgstr "这是内核指示器。当内核空闲时,它看起来就像这样。" - -#: notebook/static/notebook/js/tour.js:103 -msgid "The Kernel indicator looks like this when the Kernel is busy." -msgstr "内核指示器在内核繁忙时看起来是这样的。" - -#: notebook/static/notebook/js/tour.js:107 -msgid "Interrupting the Kernel" -msgstr "内核中断" - -#: notebook/static/notebook/js/tour.js:109 -msgid "To cancel a computation in progress, you can click here." -msgstr "要取消正在进行的计算任务,您可以点击这里。" - -#: notebook/static/notebook/js/tour.js:114 -msgid "Notification Area" -msgstr "任务栏通知区" - -#: notebook/static/notebook/js/tour.js:115 -msgid "Messages in response to user actions (Save, Interrupt, etc.) appear here." -msgstr "响应用户操作(保存,中断等)的消息出现在这里。" - -#: notebook/static/notebook/js/tour.js:117 -msgid "End of Tour" -msgstr "结束导览" - -#: notebook/static/notebook/js/tour.js:120 -msgid "This concludes the Jupyter Notebook User Interface Tour." -msgstr "Jupyter 笔记本用户界面之旅到此为止。" - -#: notebook/static/notebook/js/celltoolbarpresets/attachments.js:32 -msgid "Edit Attachments" -msgstr "编辑附件" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:19 -msgid "Cell" -msgstr "单元格" - -#: notebook/static/notebook/js/celltoolbarpresets/default.js:29 -#: notebook/static/notebook/js/celltoolbarpresets/default.js:47 -msgid "Edit Metadata" -msgstr "编辑元数据" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:22 -msgid "Custom" -msgstr "自定义" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:32 -msgid "Set the MIME type of the raw cell:" -msgstr "设置原始单元格的 MIME 类型:" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:40 -msgid "Raw Cell MIME Type" -msgstr "原始单元格的 MIME 类型" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:74 -msgid "Raw NBConvert Format" -msgstr "原始 NBConvert 类型" - -#: notebook/static/notebook/js/celltoolbarpresets/rawcell.js:81 -msgid "Raw Cell Format" -msgstr "原始单元格格式" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:15 -msgid "Slide" -msgstr "幻灯片" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:16 -msgid "Sub-Slide" -msgstr "子幻灯片" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:17 -msgid "Fragment" -msgstr "碎片" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:18 -msgid "Skip" -msgstr "跳过" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:19 -msgid "Notes" -msgstr "代码" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:35 -msgid "Slide Type" -msgstr "幻灯片类型" - -#: notebook/static/notebook/js/celltoolbarpresets/slideshow.js:41 -msgid "Slideshow" -msgstr "幻灯片" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:133 -msgid "Add tag" -msgstr "添加标签" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:163 -msgid "Edit the list of tags below. All whitespace is treated as tag separators." -msgstr "编辑下面的标签列表。所有空格都被当作标记分隔符。" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:172 -msgid "Edit the tags" -msgstr "编辑标签" - -#: notebook/static/notebook/js/celltoolbarpresets/tags.js:186 -msgid "Edit Tags" -msgstr "编辑标签" - -#: notebook/static/tree/js/kernellist.js:86 -#: notebook/static/tree/js/terminallist.js:105 -msgid "Shutdown" -msgstr "关闭" - -#: notebook/static/tree/js/newnotebook.js:70 -#, python-format -msgid "Create a new notebook with %s" -msgstr "创建新的笔记本 %s" - -#: notebook/static/tree/js/newnotebook.js:101 -msgid "An error occurred while creating a new notebook." -msgstr "创建新笔记本时出错。" - -#: notebook/static/tree/js/notebooklist.js:154 -msgid "Creating File Failed" -msgstr "创建文件失败" - -#: notebook/static/tree/js/notebooklist.js:156 -msgid "An error occurred while creating a new file." -msgstr "创建新文件时出错。" - -#: notebook/static/tree/js/notebooklist.js:174 -msgid "Creating Folder Failed" -msgstr "创建文件夹失败" - -#: notebook/static/tree/js/notebooklist.js:176 -msgid "An error occurred while creating a new folder." -msgstr "创建新文件夹时出错。" - -#: notebook/static/tree/js/notebooklist.js:271 -msgid "Failed to read file" -msgstr "读取文件失败" - -#: notebook/static/tree/js/notebooklist.js:272 -#, python-format -msgid "Failed to read file %s" -msgstr "读取文件 %s 失败了" - - -#: notebook/static/tree/js/notebooklist.js:283 -#, python-format -msgid "The file size is %d MB. Do you still want to upload it?" -msgstr "文件大小为 %d MB,依然上传?" - - -#: notebook/static/tree/js/notebooklist.js:286 -msgid "Large file size warning" -msgstr "请注意文件大小" - - -#: notebook/static/tree/js/notebooklist.js:355 -msgid "Server error: " -msgstr "服务出现错误:" - -#: notebook/static/tree/js/notebooklist.js:380 -msgid "The notebook list is empty." -msgstr "笔记本列表为空。" - - -#: notebook/static/tree/js/notebooklist.js:453 -msgid "Click here to rename, delete, etc." -msgstr "点击这里进行重命名或删除等操作" - - -#: notebook/static/tree/js/notebooklist.js:493 -msgid "Running" -msgstr "运行" - -#: notebook/static/tree/js/notebooklist.js:839 -msgid "Enter a new file name:" -msgstr "请输入一个新的文件名:" - - -#: notebook/static/tree/js/notebooklist.js:840 -msgid "Enter a new directory name:" -msgstr "请输入一个新的路径:" - - -#: notebook/static/tree/js/notebooklist.js:842 -msgid "Enter a new name:" -msgstr "请输入新名字:" - - -#: notebook/static/tree/js/notebooklist.js:847 -msgid "Rename file" -msgstr "文件重命名" - -#: notebook/static/tree/js/notebooklist.js:848 -msgid "Rename directory" -msgstr "重命名路径" - - -#: notebook/static/tree/js/notebooklist.js:849 -msgid "Rename notebook" -msgstr "重命名笔记本" - -#: notebook/static/tree/js/notebooklist.js:863 -msgid "Move" -msgstr "移动" - -#: notebook/static/tree/js/notebooklist.js:879 -msgid "An error occurred while renaming \"%1$s\" to \"%2$s\"." -msgstr "当把 \"%1$s\" 重命名为 \"%2$s\" 时出现错误." - -#: notebook/static/tree/js/notebooklist.js:882 -msgid "Rename Failed" -msgstr "重命名失败" - -#: notebook/static/tree/js/notebooklist.js:931 -#, python-format -msgid "Enter a new destination directory path for this item:" -msgid_plural "Enter a new destination directory path for these %d items:" -msgstr[0] "为笔记本选择一个新的路径:" -msgstr[1] "为选中的 %d 笔记本选择一个新的路径:" - -#: notebook/static/tree/js/notebooklist.js:944 -#, python-format -msgid "Move an Item" -msgid_plural "Move %d Items" -msgstr[0] "移动一个文件" -msgstr[1] "移动 %d 个文件" - -#: notebook/static/tree/js/notebooklist.js:963 -msgid "An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\"." -msgstr "当把 \"%1$s\" 从 \"%2$s\" 移动到 \"%3$s\" 时出现错误." - -#: notebook/static/tree/js/notebooklist.js:965 -msgid "Move Failed" -msgstr "移动失败" - -#: notebook/static/tree/js/notebooklist.js:1011 -#, python-format -msgid "Are you sure you want to permanently delete: \"%s\"?" -msgid_plural "Are you sure you want to permanently delete the %d files or folders selected?" -msgstr[0] "确定永久删除 \"%s\"?" -msgstr[1] "确定永久删除选中的 %d 个文件或文件夹?" - -#: notebook/static/tree/js/notebooklist.js:1039 -#, python-format -msgid "An error occurred while deleting \"%s\"." -msgstr "当删除 \"%s\" 时, 出现错误。" - -#: notebook/static/tree/js/notebooklist.js:1041 -msgid "Delete Failed" -msgstr "删除失败" - -#: notebook/static/tree/js/notebooklist.js:1079 -#, python-format -msgid "Are you sure you want to duplicate: \"%s\"?" -msgid_plural "Are you sure you want to duplicate the %d files selected?" -msgstr[0] "确定制作 \"%s\" 的副本?" -msgstr[1] "确定制作选中的 %d 个文件的副本?" - -#: notebook/static/tree/js/notebooklist.js:1089 -msgid "Duplicate" -msgstr "制作副本" - -#: notebook/static/tree/js/notebooklist.js:1103 -#, python-format -msgid "An error occurred while duplicating \"%s\"." -msgstr "制作 \"%s\" 的副本时出现错误。" - -#: notebook/static/tree/js/notebooklist.js:1105 -msgid "Duplicate Failed" -msgstr "制作副本失败" - -#: notebook/static/tree/js/notebooklist.js:1325 -msgid "Upload" -msgstr "上传" - -#: notebook/static/tree/js/notebooklist.js:1334 -msgid "Invalid file name" -msgstr "无效的文件名" - -#: notebook/static/tree/js/notebooklist.js:1335 -msgid "File names must be at least one character and not start with a period" -msgstr "文件名不能为空,并且不能以句号开始,除下划线以外的符号都不能开头" - -#: notebook/static/tree/js/notebooklist.js:1364 -msgid "Cannot upload invalid Notebook" -msgstr "无法上传无效的笔记本" - -#: notebook/static/tree/js/notebooklist.js:1397 -#, python-format -msgid "There is already a file named \"%s\". Do you want to replace it?" -msgstr "已经存在一个名为 \"%s\" 的文件,替换现有文件?" - -#: notebook/static/tree/js/notebooklist.js:1399 -msgid "Replace file" -msgstr "替换文件" - diff --git a/notebook/i18n/zh_CN/LC_MESSAGES/nbui.po b/notebook/i18n/zh_CN/LC_MESSAGES/nbui.po deleted file mode 100644 index cfb5ed835..000000000 --- a/notebook/i18n/zh_CN/LC_MESSAGES/nbui.po +++ /dev/null @@ -1,733 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -# Universal translation: cell=单元格; kernal=内核; don't translate notebook whenever referring to Jupyter Notebook -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-08-25 02:53-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.0\n" - -#: notebook/templates/404.html:3 -msgid "You are requesting a page that does not exist!" -msgstr "您所请求的页面不存在!" - -#: notebook/templates/edit.html:37 -msgid "current mode" -msgstr "当前模式" - -#: notebook/templates/edit.html:48 notebook/templates/notebook.html:78 -msgid "File" -msgstr "文件" - -#: notebook/templates/edit.html:50 notebook/templates/tree.html:57 -msgid "New" -msgstr "新建" - -#: notebook/templates/edit.html:51 -msgid "Save" -msgstr "保存" - -#: notebook/templates/edit.html:52 notebook/templates/tree.html:36 -msgid "Rename" -msgstr "重命名" - -#: notebook/templates/edit.html:53 notebook/templates/tree.html:38 -msgid "Download" -msgstr "下载" - -#: notebook/templates/edit.html:56 notebook/templates/notebook.html:131 -#: notebook/templates/tree.html:41 -msgid "Edit" -msgstr "编辑" - -#: notebook/templates/edit.html:58 -msgid "Find" -msgstr "查找" - -#: notebook/templates/edit.html:59 -msgid "Find & Replace" -msgstr "查找 & 替换" - -#: notebook/templates/edit.html:61 -msgid "Key Map" -msgstr "键值对" - -#: notebook/templates/edit.html:62 -msgid "Default" -msgstr "默认" - -#: notebook/templates/edit.html:63 -msgid "Sublime Text" -msgstr "代码编辑器" - -#: notebook/templates/edit.html:68 notebook/templates/notebook.html:159 -#: notebook/templates/tree.html:40 -msgid "View" -msgstr "查看" - -#: notebook/templates/edit.html:70 notebook/templates/notebook.html:162 -msgid "Show/Hide the logo and notebook title (above menu bar)" -msgstr "显示/隐藏 标题和logo" - -#: notebook/templates/edit.html:71 notebook/templates/notebook.html:163 -msgid "Toggle Header" -msgstr "显示/隐藏 标题栏" - -#: notebook/templates/edit.html:72 notebook/templates/notebook.html:171 -msgid "Toggle Line Numbers" -msgstr "显示/隐藏 行号" - -#: notebook/templates/edit.html:75 -msgid "Language" -msgstr "语言" - -#: notebook/templates/error.html:23 -msgid "The error was:" -msgstr "错误:" - -#: notebook/templates/login.html:24 -msgid "Password or token:" -msgstr "密码或者token:" - -#: notebook/templates/login.html:26 -msgid "Password:" -msgstr "密码:" - -#: notebook/templates/login.html:31 -msgid "Log in" -msgstr "登录" - -#: notebook/templates/login.html:39 -msgid "No login available, you shouldn't be seeing this page." -msgstr "还没有登录,请先登录。" - -#: notebook/templates/logout.html:31 -#, python-format -msgid "Proceed to the dashboard" -msgstr "进入 指示板" - -#: notebook/templates/logout.html:33 -#, python-format -msgid "Proceed to the login page" -msgstr "进入 登录页面" - -#: notebook/templates/notebook.html:62 -msgid "Menu" -msgstr "菜单" - -#: notebook/templates/notebook.html:65 notebook/templates/notebook.html:254 -msgid "Kernel" -msgstr "内核" - -#: notebook/templates/notebook.html:68 -msgid "This notebook is read-only" -msgstr "这个notebook文件是只读的" - -#: notebook/templates/notebook.html:81 -msgid "New Notebook" -msgstr "新建Notebook" - -#: notebook/templates/notebook.html:85 -msgid "Opens a new window with the Dashboard view" -msgstr "以仪表盘视角打开新的窗口" - -#: notebook/templates/notebook.html:86 -msgid "Open..." -msgstr "打开..." - -#: notebook/templates/notebook.html:90 -msgid "Open a copy of this notebook's contents and start a new kernel" -msgstr "复制并打开当前notebook的内容,并启动一个新的内核" - -#: notebook/templates/notebook.html:91 -msgid "Make a Copy..." -msgstr "复制..." - -#: notebook/templates/notebook.html:92 -msgid "Rename..." -msgstr "重命名..." - -#: notebook/templates/notebook.html:93 -msgid "Save and Checkpoint" -msgstr "保存,且作为一个检查点" - -#: notebook/templates/notebook.html:96 -msgid "Revert to Checkpoint" -msgstr "恢复到某一个检查点" - -#: notebook/templates/notebook.html:106 -msgid "Print Preview" -msgstr "打印预览" - -#: notebook/templates/notebook.html:107 -msgid "Download as" -msgstr "另存为" - -#: notebook/templates/notebook.html:109 -msgid "Notebook (.ipynb)" -msgstr "Notebook (.ipynb)" - -#: notebook/templates/notebook.html:110 -msgid "Script" -msgstr "脚本" - -#: notebook/templates/notebook.html:111 -msgid "HTML (.html)" -msgstr "" - -#: notebook/templates/notebook.html:112 -msgid "Markdown (.md)" -msgstr "" - -#: notebook/templates/notebook.html:113 -msgid "reST (.rst)" -msgstr "" - -#: notebook/templates/notebook.html:114 -msgid "LaTeX (.tex)" -msgstr "" - -#: notebook/templates/notebook.html:115 -msgid "PDF via LaTeX (.pdf)" -msgstr "通过LaTeX生成的PDF (.pdf)" - -#: notebook/templates/notebook.html:118 -msgid "Deploy as" -msgstr "部署在" - -#: notebook/templates/notebook.html:123 -msgid "Trust the output of this notebook" -msgstr "信任当前notebook的输出" - -#: notebook/templates/notebook.html:124 -msgid "Trust Notebook" -msgstr "信任当前Notebook" - -#: notebook/templates/notebook.html:127 -msgid "Shutdown this notebook's kernel, and close this window" -msgstr "关闭当前notebook的内核,并关闭当前窗口" - -#: notebook/templates/notebook.html:128 -msgid "Close and Halt" -msgstr "关闭" - -#: notebook/templates/notebook.html:133 -msgid "Cut Cells" -msgstr "剪切单元格" - -#: notebook/templates/notebook.html:134 -msgid "Copy Cells" -msgstr "复制单元格" - -#: notebook/templates/notebook.html:135 -msgid "Paste Cells Above" -msgstr "粘贴单元格到上面" - -#: notebook/templates/notebook.html:136 -msgid "Paste Cells Below" -msgstr "粘贴单元格到下面" - -#: notebook/templates/notebook.html:137 -msgid "Paste Cells & Replace" -msgstr "粘贴单元格 & 替换" - -#: notebook/templates/notebook.html:138 -msgid "Delete Cells" -msgstr "删除单元格" - -#: notebook/templates/notebook.html:139 -msgid "Undo Delete Cells" -msgstr "撤销删除单元格" - -#: notebook/templates/notebook.html:141 -msgid "Split Cell" -msgstr "分割单元格" - -#: notebook/templates/notebook.html:142 -msgid "Merge Cell Above" -msgstr "合并上面的单元格" - -#: notebook/templates/notebook.html:143 -msgid "Merge Cell Below" -msgstr "合并下面的单元格" - -#: notebook/templates/notebook.html:145 -msgid "Move Cell Up" -msgstr "上移单元格" - -#: notebook/templates/notebook.html:146 -msgid "Move Cell Down" -msgstr "下移单元格" - -#: notebook/templates/notebook.html:148 -msgid "Edit Notebook Metadata" -msgstr "编辑Notebook的元数据" - -#: notebook/templates/notebook.html:150 -msgid "Find and Replace" -msgstr "查找并替换" - -#: notebook/templates/notebook.html:152 -msgid "Cut Cell Attachments" -msgstr "剪切附件" - -#: notebook/templates/notebook.html:153 -msgid "Copy Cell Attachments" -msgstr "复制附件" - -#: notebook/templates/notebook.html:154 -msgid "Paste Cell Attachments" -msgstr "粘贴附件" - -#: notebook/templates/notebook.html:156 -msgid "Insert Image" -msgstr "插入图片" - -#: notebook/templates/notebook.html:166 -msgid "Show/Hide the action icons (below menu bar)" -msgstr "显示/隐藏 操作图标" - -#: notebook/templates/notebook.html:167 -msgid "Toggle Toolbar" -msgstr "显示/隐藏 工具栏" - -#: notebook/templates/notebook.html:170 -msgid "Show/Hide line numbers in cells" -msgstr "显示/隐藏 当前单元格的行号" - -#: notebook/templates/notebook.html:174 -msgid "Cell Toolbar" -msgstr "单元格 工具栏" - -#: notebook/templates/notebook.html:179 -msgid "Insert" -msgstr "插入" - -#: notebook/templates/notebook.html:182 -msgid "Insert an empty Code cell above the currently active cell" -msgstr "在当前代码块上面插入一个空的单元格" - -#: notebook/templates/notebook.html:183 -msgid "Insert Cell Above" -msgstr "在上面插入一个单元格" - -#: notebook/templates/notebook.html:185 -msgid "Insert an empty Code cell below the currently active cell" -msgstr "在当前代码块下面插入一个空的单元格" - -#: notebook/templates/notebook.html:186 -msgid "Insert Cell Below" -msgstr "在下面插入一个单元格" - -#: notebook/templates/notebook.html:189 -msgid "Cell" -msgstr "单元格" - -#: notebook/templates/notebook.html:191 -msgid "Run this cell, and move cursor to the next one" -msgstr "运行此单元格,并将光标移到下一个" - -#: notebook/templates/notebook.html:192 -msgid "Run Cells" -msgstr "运行所有单元格" - -#: notebook/templates/notebook.html:193 -msgid "Run this cell, select below" -msgstr "运行此单元格,并自动选择下一个" - -#: notebook/templates/notebook.html:194 -msgid "Run Cells and Select Below" -msgstr "运行所有单元格,并自动选择下一个" - -#: notebook/templates/notebook.html:195 -msgid "Run this cell, insert below" -msgstr "运行此单元格,并在下面插入一个新的单元格" - -#: notebook/templates/notebook.html:196 -msgid "Run Cells and Insert Below" -msgstr "运行所有单元格,并在下面插入一个新的单元格" - -#: notebook/templates/notebook.html:197 -msgid "Run all cells in the notebook" -msgstr "运行所有的单元格" - -#: notebook/templates/notebook.html:198 -msgid "Run All" -msgstr "运行所有" - -#: notebook/templates/notebook.html:199 -msgid "Run all cells above (but not including) this cell" -msgstr "运行上面所有的单元格(但不包括这个单元格)" - -#: notebook/templates/notebook.html:200 -msgid "Run All Above" -msgstr "运行上面所有的单元格" - -#: notebook/templates/notebook.html:201 -msgid "Run this cell and all cells below it" -msgstr "运行当前及以下所有的单元格" - -#: notebook/templates/notebook.html:202 -msgid "Run All Below" -msgstr "运行下面的所有的单元格" - -#: notebook/templates/notebook.html:205 -msgid "All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells" -msgstr "Notebook里的所有单元格都有一个类型。默认新单元格都会被创建为代码单元格" - -#: notebook/templates/notebook.html:206 -msgid "Cell Type" -msgstr "单元格类型" - -#: notebook/templates/notebook.html:209 -msgid "Contents will be sent to the kernel for execution, and output will display in the footer of cell" -msgstr "内容将被发送到内核执行,输出将显示在单元格的页脚" - -#: notebook/templates/notebook.html:212 -msgid "Contents will be rendered as HTML and serve as explanatory text" -msgstr "内容将以HTML形式呈现, 并作为解释性文本" - -#: notebook/templates/notebook.html:213 notebook/templates/notebook.html:298 -msgid "Markdown" -msgstr "" - -#: notebook/templates/notebook.html:215 -msgid "Contents will pass through nbconvert unmodified" -msgstr "内容将通过nbconvert且不会被修改" - -#: notebook/templates/notebook.html:216 -msgid "Raw NBConvert" -msgstr "原生 NBConvert" - -#: notebook/templates/notebook.html:220 -msgid "Current Outputs" -msgstr "当前输出" - -#: notebook/templates/notebook.html:223 -msgid "Hide/Show the output of the current cell" -msgstr "隐藏/显示当前单元格输出" - -#: notebook/templates/notebook.html:224 notebook/templates/notebook.html:240 -msgid "Toggle" -msgstr "显示/隐藏" - -#: notebook/templates/notebook.html:227 -msgid "Scroll the output of the current cell" -msgstr "滚动到当前单元格的输出" - -#: notebook/templates/notebook.html:228 notebook/templates/notebook.html:244 -msgid "Toggle Scrolling" -msgstr "滚动显示" - -#: notebook/templates/notebook.html:231 -msgid "Clear the output of the current cell" -msgstr "清除当前单元格的输出" - -#: notebook/templates/notebook.html:232 notebook/templates/notebook.html:248 -msgid "Clear" -msgstr "清空" - -#: notebook/templates/notebook.html:236 -msgid "All Output" -msgstr "所有输出" - -#: notebook/templates/notebook.html:239 -msgid "Hide/Show the output of all cells" -msgstr "隐藏/显示 所有单元格的输出" - -#: notebook/templates/notebook.html:243 -msgid "Scroll the output of all cells" -msgstr "切换所有单元格的输出为滚动模式" - -#: notebook/templates/notebook.html:247 -msgid "Clear the output of all cells" -msgstr "清空所有代码块的输出" - -#: notebook/templates/notebook.html:257 -msgid "Send Keyboard Interrupt (CTRL-C) to the Kernel" -msgstr "按下 CTRL-C 中断内核" - -#: notebook/templates/notebook.html:258 -msgid "Interrupt" -msgstr "中断" - -#: notebook/templates/notebook.html:261 -msgid "Restart the Kernel" -msgstr "重启内核" - -#: notebook/templates/notebook.html:262 -msgid "Restart" -msgstr "重启" - -#: notebook/templates/notebook.html:265 -msgid "Restart the Kernel and clear all output" -msgstr "重启服务并清空所有输出" - -#: notebook/templates/notebook.html:266 -msgid "Restart & Clear Output" -msgstr "重启 & 清空输出" - -#: notebook/templates/notebook.html:269 -msgid "Restart the Kernel and re-run the notebook" -msgstr "重启内核并且重新运行整个notebook" - -#: notebook/templates/notebook.html:270 -msgid "Restart & Run All" -msgstr "重启 & 运行所有" - -#: notebook/templates/notebook.html:273 -msgid "Reconnect to the Kernel" -msgstr "重连内核" - -#: notebook/templates/notebook.html:274 -msgid "Reconnect" -msgstr "重连" - -#: notebook/templates/notebook.html:282 -msgid "Change kernel" -msgstr "更换内核" - -#: notebook/templates/notebook.html:287 -msgid "Help" -msgstr "帮助" - -#: notebook/templates/notebook.html:290 -msgid "A quick tour of the notebook user interface" -msgstr "快速浏览一下notebook用户界面" - -#: notebook/templates/notebook.html:290 -msgid "User Interface Tour" -msgstr "用户界面之旅" - -#: notebook/templates/notebook.html:291 -msgid "Opens a tooltip with all keyboard shortcuts" -msgstr "打开包含所有快捷键的提示信息" - -#: notebook/templates/notebook.html:291 -msgid "Keyboard Shortcuts" -msgstr "快捷键" - -#: notebook/templates/notebook.html:292 -msgid "Opens a dialog allowing you to edit Keyboard shortcuts" -msgstr "打开对话框编辑快捷键" - -#: notebook/templates/notebook.html:292 -msgid "Edit Keyboard Shortcuts" -msgstr "编辑快捷键" - -#: notebook/templates/notebook.html:297 -msgid "Notebook Help" -msgstr "帮助" - -#: notebook/templates/notebook.html:303 -msgid "Opens in a new window" -msgstr "在新窗口打开" - -#: notebook/templates/notebook.html:319 -msgid "About Jupyter Notebook" -msgstr "关于本程序" - -#: notebook/templates/notebook.html:319 -msgid "About" -msgstr "关于" - -#: notebook/templates/page.html:114 -msgid "Jupyter Notebook requires JavaScript." -msgstr "Jupyter Notebook 需要 JavaScript。" - -#: notebook/templates/page.html:115 -msgid "Please enable it to proceed. " -msgstr "请启用它以继续。" - -#: notebook/templates/page.html:122 -msgid "dashboard" -msgstr "指示板" - -#: notebook/templates/page.html:135 -msgid "Logout" -msgstr "注销" - -#: notebook/templates/page.html:137 -msgid "Login" -msgstr "登录" - -#: notebook/templates/tree.html:23 -msgid "Files" -msgstr "文件" - -#: notebook/templates/tree.html:24 -msgid "Running" -msgstr "运行" - -#: notebook/templates/tree.html:25 -msgid "Clusters" -msgstr "集群" - -#: notebook/templates/tree.html:32 -msgid "Select items to perform actions on them." -msgstr "选择操作对象." - -#: notebook/templates/tree.html:35 -msgid "Duplicate selected" -msgstr "复制选中的对象" - -#: notebook/templates/tree.html:35 -msgid "Duplicate" -msgstr "复制" - -#: notebook/templates/tree.html:36 -msgid "Rename selected" -msgstr "重命名选中的对象" - -#: notebook/templates/tree.html:37 -msgid "Move selected" -msgstr "移动选中的对象" - -#: notebook/templates/tree.html:37 -msgid "Move" -msgstr "移动" - -#: notebook/templates/tree.html:38 -msgid "Download selected" -msgstr "下载选中的对象" - -#: notebook/templates/tree.html:39 -msgid "Shutdown selected notebook(s)" -msgstr "停止运行选择的notebook(s)" - -#: notebook/templates/notebook.html:278 -#: notebook/templates/tree.html:39 -msgid "Shutdown" -msgstr "关闭" - -#: notebook/templates/tree.html:40 -msgid "View selected" -msgstr "查看选中的对象" - -#: notebook/templates/tree.html:41 -msgid "Edit selected" -msgstr "编辑选中的对象" - -#: notebook/templates/tree.html:42 -msgid "Delete selected" -msgstr "删除选中的对象" - -#: notebook/templates/tree.html:50 -msgid "Click to browse for a file to upload." -msgstr "浏览文件并上传" - -#: notebook/templates/tree.html:51 -msgid "Upload" -msgstr "上传" - -#: notebook/templates/tree.html:65 -msgid "Text File" -msgstr "文本文件" - -#: notebook/templates/tree.html:68 -msgid "Folder" -msgstr "文件夹" - -#: notebook/templates/tree.html:72 -msgid "Terminal" -msgstr "终端" - -#: notebook/templates/tree.html:76 -msgid "Terminals Unavailable" -msgstr "终端不可用" - -#: notebook/templates/tree.html:82 -msgid "Refresh notebook list" -msgstr "刷新笔记列表" - -#: notebook/templates/tree.html:90 -msgid "Select All / None" -msgstr "全选 / 全不选" - -#: notebook/templates/tree.html:93 -msgid "Select..." -msgstr "选择..." - -#: notebook/templates/tree.html:98 -msgid "Select All Folders" -msgstr "选择所有文件夹" - -#: notebook/templates/tree.html:98 -msgid "Folders" -msgstr "文件夹" - -#: notebook/templates/tree.html:99 -msgid "Select All Notebooks" -msgstr "选择所有Notebooks" - -#: notebook/templates/tree.html:99 -msgid "All Notebooks" -msgstr "所有Notebooks" - -#: notebook/templates/tree.html:100 -msgid "Select Running Notebooks" -msgstr "选择运行中的Notebooks" - -#: notebook/templates/tree.html:100 -msgid "Running" -msgstr "运行" - -#: notebook/templates/tree.html:101 -msgid "Select All Files" -msgstr "选择所有文件" - -#: notebook/templates/tree.html:101 -msgid "Files" -msgstr "文件" - -#: notebook/templates/tree.html:114 -msgid "Last Modified" -msgstr "最后修改" - -#: notebook/templates/tree.html:120 -msgid "Name" -msgstr "名字" - -#: notebook/templates/tree.html:130 -msgid "Currently running Jupyter processes" -msgstr "当前运行Jupyter" - -#: notebook/templates/tree.html:134 -msgid "Refresh running list" -msgstr "刷新运行列表" - -#: notebook/templates/tree.html:150 -msgid "There are no terminals running." -msgstr "没有终端正在运行。" - -#: notebook/templates/tree.html:152 -msgid "Terminals are unavailable." -msgstr "终端不可用。" - -#: notebook/templates/tree.html:162 -msgid "Notebooks" -msgstr "" - -#: notebook/templates/tree.html:169 -msgid "There are no notebooks running." -msgstr "没有notebooks正在运行。" - -#: notebook/templates/tree.html:178 -msgid "Clusters tab is now provided by IPython parallel." -msgstr "集群标签现在由IPython并行提供。" - -#: notebook/templates/tree.html:179 -msgid "See 'IPython parallel' for installation details." -msgstr "安装细节查看 'IPython parallel'。" - diff --git a/notebook/i18n/zh_CN/LC_MESSAGES/notebook.po b/notebook/i18n/zh_CN/LC_MESSAGES/notebook.po deleted file mode 100644 index aa03cd583..000000000 --- a/notebook/i18n/zh_CN/LC_MESSAGES/notebook.po +++ /dev/null @@ -1,486 +0,0 @@ -# Translations template for Jupyter. -# Copyright (C) 2017 ORGANIZATION -# This file is distributed under the same license as the Jupyter project. -# FIRST AUTHOR , 2017. -# -#, fuzzy -# Universal translation: cell=单元格; kernal=内核; don't translate notebook whenever referring to Jupyter Notebook -msgid "" -msgstr "" -"Project-Id-Version: Jupyter VERSION\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-08-25 02:53-0400\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.0\n" - -#: notebook/notebookapp.py:49 -msgid "The Jupyter Notebook requires tornado >= 4.0" -msgstr "Jupyter Notebook要求拥有 tornado 版本号 >= 4.0" - -#: notebook/notebookapp.py:53 -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have < 1.1.0" -msgstr "Jupyter Notebook要求拥有 tornado 版本号 >= 4.0, 但你的版本号却是 < 1.1.0" - -#: notebook/notebookapp.py:55 -#, python-format -msgid "The Jupyter Notebook requires tornado >= 4.0, but you have %s" -msgstr "Jupyter Notebook要求拥有 tornado 版本号 >= 4.0, 但你的版本号却是 %s" - -#: notebook/notebookapp.py:205 -msgid "The `ignore_minified_js` flag is deprecated and no longer works." -msgstr "`ignore_minified_js` 这个标志已经被弃用且不再工作。" - -#: notebook/notebookapp.py:206 -#, python-format -msgid "Alternatively use `%s` when working on the notebook's Javascript and LESS" -msgstr "在使用notebook的JavaScript和LESS时,可以替换使用 `%s` " - -#: notebook/notebookapp.py:207 -msgid "The `ignore_minified_js` flag is deprecated and will be removed in Notebook 6.0" -msgstr "`ignore_minified_js` 这个标志已经被弃用,且会在Notebook 6.0版本时被移除" - -#: notebook/notebookapp.py:385 -msgid "List currently running notebook servers." -msgstr "列出当前运行的Notebook服务。" - -#: notebook/notebookapp.py:389 -msgid "Produce machine-readable JSON list output." -msgstr "生成机器可读的JSON输出。" - -#: notebook/notebookapp.py:391 -msgid "Produce machine-readable JSON object on each line of output." -msgstr "在每一行输出上生成机器可读的JSON。" - -#: notebook/notebookapp.py:395 -msgid "If True, the output will be a JSON list of objects, one per active notebook server, each with the details from the relevant server info file." -msgstr "如果是正确的,输出将是一个对象的JSON列表,每个活动的笔记本服务器都有一个,每一个都有相关的服务器信息文件的详细信息。" - -#: notebook/notebookapp.py:399 -msgid "If True, each line of output will be a JSON object with the details from the server info file. For a JSON list output, see the NbserverListApp.jsonlist configuration value" -msgstr "如果是正确的,每一行输出将是一个JSON对象,且包含来自服务器信息文件的详细信息。对于一个JSON列表输出,请参阅NbserverListApp.jsonlist配置值" - -#: notebook/notebookapp.py:425 -msgid "Don't open the notebook in a browser after startup." -msgstr "请不要在启动服务以后在浏览器中打开notebook。" - -#: notebook/notebookapp.py:429 -msgid "DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib." -msgstr "尚未启用!请在notebook中使用 %pylab or %matplotlib 指令来启用 matplotlib 包。" - -#: notebook/notebookapp.py:445 -msgid "Allow the notebook to be run from root user." -msgstr "允许notebook在root用户下运行。" - -#: notebook/notebookapp.py:476 -msgid "" -"The Jupyter HTML Notebook.\n" -" \n" -" This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client." -msgstr "The Jupyter HTML Notebook.\n \n 这将启动一个基于tornado的HTML Notebook服务器,并提供一个HTML5/Javascript Notebook客户端。" - -#: notebook/notebookapp.py:515 -msgid "Deprecated: Use minified JS file or not, mainly use during dev to avoid JS recompilation" -msgstr "" - -#: notebook/notebookapp.py:546 -msgid "Set the Access-Control-Allow-Credentials: true header" -msgstr "请把Access-Control-Allow-Credentials设置为:true header" - -#: notebook/notebookapp.py:550 -msgid "Whether to allow the user to run the notebook as root." -msgstr "是否允许notebook在root用户下运行。" - -#: notebook/notebookapp.py:554 -msgid "The default URL to redirect to from `/`" -msgstr "从 `/` 重定向到的默认URL " - -#: notebook/notebookapp.py:558 -msgid "The IP address the notebook server will listen on." -msgstr "notebook服务会监听的IP地址。" - -#: notebook/notebookapp.py:571 -#, python-format -msgid "" -"Cannot bind to localhost, using 127.0.0.1 as default ip\n" -"%s" -msgstr "不能绑定到localhost, 请使用127.0.0.1作为默认的IP \n %s" - -#: notebook/notebookapp.py:585 -msgid "The port the notebook server will listen on." -msgstr "notebook服务会监听的IP端口。" - -#: notebook/notebookapp.py:589 -msgid "The number of additional ports to try if the specified port is not available." -msgstr "如果指定的端口不可用,则要尝试其他端口的数量。" - -#: notebook/notebookapp.py:593 -msgid "The full path to an SSL/TLS certificate file." -msgstr "SSL/TLS 认证文件所在的完整路径。" - -#: notebook/notebookapp.py:597 -msgid "The full path to a private key file for usage with SSL/TLS." -msgstr "SSL/TLS 私钥文件所在的完整路径。" - -#: notebook/notebookapp.py:601 -msgid "The full path to a certificate authority certificate for SSL/TLS client authentication." -msgstr "SSL/TLS 客户端身份验证的证书所在的完整路径。" - -#: notebook/notebookapp.py:605 -msgid "The file where the cookie secret is stored." -msgstr "那个存放cookie密钥的文件。" - -#: notebook/notebookapp.py:634 -#, python-format -msgid "Writing notebook server cookie secret to %s" -msgstr "把notebook服务器的cookie密码写入 %s" - -#: notebook/notebookapp.py:641 -#, python-format -msgid "Could not set permissions on %s" -msgstr "无法在 %s 设置权限" - -#: notebook/notebookapp.py:646 -msgid "" -"Token used for authenticating first-time connections to the server.\n" -"\n" -" When no password is enabled,\n" -" the default is to generate a new, random token.\n" -"\n" -" Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED.\n" -" " -msgstr "服务器第一次连接所需要的认证秘钥。\n \n 如果没有弃用密码,\n 默认将生成一个新的随机秘钥。\n \n 由于设置为一个空白字段会自动关闭认证,我们不推荐该行为。\n" - -#: notebook/notebookapp.py:656 -msgid "" -"One-time token used for opening a browser.\n" -" Once used, this token cannot be used again.\n" -" " -msgstr "打开浏览器的一次性秘钥。\n 一旦使用,则无法再次使用。\n" - -#: notebook/notebookapp.py:732 -msgid "" -"Specify Where to open the notebook on startup. This is the\n" -" `new` argument passed to the standard library method `webbrowser.open`.\n" -" The behaviour is not guaranteed, but depends on browser support. Valid\n" -" values are:\n" -" 2 opens a new tab,\n" -" 1 opens a new window,\n" -" 0 opens in an existing window.\n" -" See the `webbrowser.open` documentation for details.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:743 -msgid "DEPRECATED, use tornado_settings" -msgstr "已被弃用!请使用 tornado_settings" - -#: notebook/notebookapp.py:748 -msgid "" -"\n" -" webapp_settings is deprecated, use tornado_settings.\n" -msgstr "webapp_settings已被弃用,请使用tornado_settings。" - -#: notebook/notebookapp.py:752 -msgid "Supply overrides for the tornado.web.Application that the Jupyter notebook uses." -msgstr "Supply重写了Jupyter notebook正在使用的tornado.web.Application。" - -#: notebook/notebookapp.py:756 -msgid "" -"\n" -" Set the tornado compression options for websocket connections.\n" -"\n" -" This value will be returned from :meth:`WebSocketHandler.get_compression_options`.\n" -" None (default) will disable compression.\n" -" A dict (even an empty one) will enable compression.\n" -"\n" -" See the tornado docs for WebSocketHandler.get_compression_options for details.\n" -" " -msgstr "" - -#: notebook/notebookapp.py:767 -msgid "Supply overrides for terminado. Currently only supports \"shell_command\"." -msgstr "" - -#: notebook/notebookapp.py:770 -msgid "Extra keyword arguments to pass to `set_secure_cookie`. See tornado's set_secure_cookie docs for details." -msgstr "" - -#: notebook/notebookapp.py:774 -msgid "" -"Supply SSL options for the tornado HTTPServer.\n" -" See the tornado docs for details." -msgstr "" - -#: notebook/notebookapp.py:778 -msgid "Supply extra arguments that will be passed to Jinja environment." -msgstr "请添加Jinja环境所需要的额外的变量。" - -#: notebook/notebookapp.py:782 -msgid "Extra variables to supply to jinja templates when rendering." -msgstr "需要额外的变量去渲染Jinja模板。" - -#: notebook/notebookapp.py:818 -msgid "DEPRECATED use base_url" -msgstr "已被弃用!请使用 base_url" - -#: notebook/notebookapp.py:822 -msgid "base_project_url is deprecated, use base_url" -msgstr "base_project_url已被弃用!请使用 base_url" - -#: notebook/notebookapp.py:838 -msgid "Path to search for custom.js, css" -msgstr "搜索custom.js, css所在的路径" - -#: notebook/notebookapp.py:850 -msgid "" -"Extra paths to search for serving jinja templates.\n" -"\n" -" Can be used to override templates from notebook.templates." -msgstr "额外寻找Jinja模板的路径。\n \n 可以被用来覆盖 notebook.templates 里的模板" - -#: notebook/notebookapp.py:861 -msgid "extra paths to look for Javascript notebook extensions" -msgstr "额外寻找Javascript notebook扩展的路径" - -#: notebook/notebookapp.py:906 -#, python-format -msgid "Using MathJax: %s" -msgstr "" - -#: notebook/notebookapp.py:909 -msgid "The MathJax.js configuration file that is to be used." -msgstr "" - -#: notebook/notebookapp.py:914 -#, python-format -msgid "Using MathJax configuration file: %s" -msgstr "" - -#: notebook/notebookapp.py:920 -msgid "The notebook manager class to use." -msgstr "" - -#: notebook/notebookapp.py:926 -msgid "The kernel manager class to use." -msgstr "" - -#: notebook/notebookapp.py:932 -msgid "The session manager class to use." -msgstr "" - -#: notebook/notebookapp.py:938 -msgid "The config manager class to use" -msgstr "" - -#: notebook/notebookapp.py:959 -msgid "The login handler class to use." -msgstr "" - -#: notebook/notebookapp.py:966 -msgid "The logout handler class to use." -msgstr "" - -#: notebook/notebookapp.py:970 -msgid "Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headerssent by the upstream reverse proxy. Necessary if the proxy handles SSL" -msgstr "" - -#: notebook/notebookapp.py:982 -msgid "" -"\n" -" DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.\n" -" " -msgstr "\n 尚未启用!请在Notebook里使用 %pylab or %matplotlib 指令去启用matplotlib。\n" - -#: notebook/notebookapp.py:994 -msgid "Support for specifying --pylab on the command line has been removed." -msgstr "不再支持在命令行里使用 --pylab 指令。" - -#: notebook/notebookapp.py:996 -msgid "Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself." -msgstr "请在notebook里使用 %pylab{0}` or `%matplotlib{0}`。" - -#: notebook/notebookapp.py:1001 -msgid "The directory to use for notebooks and kernels." -msgstr "用于notebooks和内核的目录。" - -#: notebook/notebookapp.py:1024 -#, python-format -msgid "No such notebook dir: '%r'" -msgstr "没有找到notebook的路径: '%r' " - -#: notebook/notebookapp.py:1037 -msgid "DEPRECATED use the nbserver_extensions dict instead" -msgstr "已被弃用!请使用 nbserver_extensions dict 指令" - -#: notebook/notebookapp.py:1042 -msgid "server_extensions is deprecated, use nbserver_extensions" -msgstr "server_extensions指令已被弃用,请使用nbserver_extensions" - -#: notebook/notebookapp.py:1046 -msgid "Dict of Python modules to load as notebook server extensions.Entry values can be used to enable and disable the loading ofthe extensions. The extensions will be loaded in alphabetical order." -msgstr "可被作为notebook服务器扩展的Python模块们。可以使用条目值来启用和禁用扩展的加载。这些扩展将以字母顺序加载。" - -#: notebook/notebookapp.py:1055 -msgid "Reraise exceptions encountered loading server extensions?" -msgstr "加载服务器扩展时,遇到重新引发的异常?" - -#: notebook/notebookapp.py:1058 -msgid "" -"(msgs/sec)\n" -" Maximum rate at which messages can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/notebookapp.py:1062 -msgid "" -"(bytes/sec)\n" -" Maximum rate at which stream output can be sent on iopub before they are\n" -" limited." -msgstr "" - -#: notebook/notebookapp.py:1066 -msgid "" -"(sec) Time window used to \n" -" check the message and data rate limits." -msgstr "(sec)时间窗口被用来 \n 检查消息和限制数据速率。" - -#: notebook/notebookapp.py:1077 -#, python-format -msgid "No such file or directory: %s" -msgstr "找不到文件或文件夹: %s" - -#: notebook/notebookapp.py:1147 -msgid "Notebook servers are configured to only be run with a password." -msgstr "Notebook服务器被设置为只能使用密码运行。" - -#: notebook/notebookapp.py:1148 -msgid "Hint: run the following command to set a password" -msgstr "提示: 运行下面命令设置密码" - -#: notebook/notebookapp.py:1149 -msgid "\t$ python -m notebook.auth password" -msgstr "\t$ python -m notebook.auth password" - -#: notebook/notebookapp.py:1187 -#, python-format -msgid "The port %i is already in use, trying another port." -msgstr "端口 %i 已经被占用, 请尝试其他端口。" - -#: notebook/notebookapp.py:1190 -#, python-format -msgid "Permission to listen on port %i denied" -msgstr "没有监听端口 %i 的权限" - -#: notebook/notebookapp.py:1199 -msgid "ERROR: the notebook server could not be started because no available port could be found." -msgstr "错误: Notebook服务器启动失败 - 因为没有找到可用的端口。" - -#: notebook/notebookapp.py:1205 -msgid "[all ip addresses on your system]" -msgstr "[系统所有IP地址]" - -#: notebook/notebookapp.py:1229 -#, python-format -msgid "Terminals not available (error was %s)" -msgstr "终端不可用(错误: %s)" - -#: notebook/notebookapp.py:1265 -msgid "interrupted" -msgstr "中断" - -#: notebook/notebookapp.py:1267 -msgid "y" -msgstr "" - -#: notebook/notebookapp.py:1268 -msgid "n" -msgstr "" - -#: notebook/notebookapp.py:1269 -#, python-format -msgid "Shutdown this notebook server (%s/[%s])? " -msgstr "关闭这个notebook服务器 (%s/[%s])" - -#: notebook/notebookapp.py:1275 -msgid "Shutdown confirmed" -msgstr "确认关闭" - -#: notebook/notebookapp.py:1279 -msgid "No answer for 5s:" -msgstr "5秒未响应" - -#: notebook/notebookapp.py:1280 -msgid "resuming operation..." -msgstr "重启操作..." - -#: notebook/notebookapp.py:1288 -#, python-format -msgid "received signal %s, stopping" -msgstr "接受信号 %s, 正在停止" - -#: notebook/notebookapp.py:1344 -#, python-format -msgid "Error loading server extension %s" -msgstr "加载插件 %s 失败" - -#: notebook/notebookapp.py:1375 -#, python-format -msgid "Shutting down %d kernel" -msgid_plural "Shutting down %d kernels" -msgstr[0] "关闭 %d 内核" -msgstr[1] "关闭 %d 内核" - -#: notebook/notebookapp.py:1383 -#, python-format -msgid "%d active kernel" -msgid_plural "%d active kernels" -msgstr[0] "%d 活跃的内核" -msgstr[1] "%d 活跃的内核" - -#: notebook/notebookapp.py:1387 -#, python-format -msgid "" -"The Jupyter Notebook is running at:\n" -"%s" -msgstr "Jupyter Notebook运行在:\n %s" - -#: notebook/notebookapp.py:1434 -msgid "Running as root is not recommended. Use --allow-root to bypass." -msgstr "不建议以root身份运行。请使用 --allow-root 绕过。" - -#: notebook/notebookapp.py:1440 -msgid "Use Control-C to stop this server and shut down all kernels (twice to skip confirmation)." -msgstr "使用 Control-C 停止此服务器并关闭所有内核(连续操作两次便可跳过确认界面)。" - -#: notebook/notebookapp.py:1442 -msgid "Welcome to Project Jupyter! Explore the various tools available and their corresponding documentation. If you are interested in contributing to the platform, please visit the communityresources section at http://jupyter.org/community.html." -msgstr "欢迎来到Jupyter项目! 探索可用的各种工具及其相应的文档。如果你有兴趣对这个平台,请访问http://jupyter.org/community.html 的community resources部分。" - -#: notebook/notebookapp.py:1453 -#, python-format -msgid "No web browser found: %s." -msgstr "没有找到网页浏览器: %s。" - -#: notebook/notebookapp.py:1458 -#, python-format -msgid "%s does not exist" -msgstr "%s 不存在" - -#: notebook/notebookapp.py:1492 -msgid "Interrupted..." -msgstr "已经中断..." - -#: notebook/services/contents/filemanager.py:525 -#, python-format -msgid "Serving notebooks from local directory: %s" -msgstr "notebooks 运行所在的本地路径: %s" - -#: notebook/services/contents/manager.py:69 -msgid "Untitled" -msgstr "未命名" - diff --git a/notebook/jstest.py b/notebook/jstest.py deleted file mode 100644 index 2bb318af3..000000000 --- a/notebook/jstest.py +++ /dev/null @@ -1,615 +0,0 @@ -"""Notebook Javascript Test Controller - -This module runs one or more subprocesses which will actually run the Javascript -test suite. -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import argparse -import json -import multiprocessing.pool -import os -import re -import requests -import signal -import sys -import subprocess -import time -from io import BytesIO -from threading import Thread, Lock, Event - -from unittest.mock import patch - -from jupyter_core.paths import jupyter_runtime_dir -from ipython_genutils.py3compat import bytes_to_str, which -from notebook._sysinfo import get_sys_info -from ipython_genutils.tempdir import TemporaryDirectory - -from subprocess import TimeoutExpired -def popen_wait(p, timeout): - return p.wait(timeout) - -NOTEBOOK_SHUTDOWN_TIMEOUT = 10 - -have = {} -have['casperjs'] = bool(which('casperjs')) -have['phantomjs'] = bool(which('phantomjs')) -have['slimerjs'] = bool(which('slimerjs')) - -class StreamCapturer(Thread): - daemon = True # Don't hang if main thread crashes - started = False - def __init__(self, echo=False): - super().__init__() - self.echo = echo - self.streams = [] - self.buffer = BytesIO() - self.readfd, self.writefd = os.pipe() - self.buffer_lock = Lock() - self.stop = Event() - - def run(self): - self.started = True - - while not self.stop.is_set(): - chunk = os.read(self.readfd, 1024) - - with self.buffer_lock: - self.buffer.write(chunk) - if self.echo: - sys.stdout.write(bytes_to_str(chunk)) - - os.close(self.readfd) - os.close(self.writefd) - - def reset_buffer(self): - with self.buffer_lock: - self.buffer.truncate(0) - self.buffer.seek(0) - - def get_buffer(self): - with self.buffer_lock: - return self.buffer.getvalue() - - def ensure_started(self): - if not self.started: - self.start() - - def halt(self): - """Safely stop the thread.""" - if not self.started: - return - - self.stop.set() - os.write(self.writefd, b'\0') # Ensure we're not locked in a read() - self.join() - - -class TestController(object): - """Run tests in a subprocess - """ - #: str, test group to be executed. - section = None - #: list, command line arguments to be executed - cmd = None - #: dict, extra environment variables to set for the subprocess - env = None - #: list, TemporaryDirectory instances to clear up when the process finishes - dirs = None - #: subprocess.Popen instance - process = None - #: str, process stdout+stderr - stdout = None - - def __init__(self): - self.cmd = [] - self.env = {} - self.dirs = [] - - def setup(self): - """Create temporary directories etc. - - This is only called when we know the test group will be run. Things - created here may be cleaned up by self.cleanup(). - """ - pass - - def launch(self, buffer_output=False, capture_output=False): - # print('*** ENV:', self.env) # dbg - # print('*** CMD:', self.cmd) # dbg - env = os.environ.copy() - env.update(self.env) - if buffer_output: - capture_output = True - self.stdout_capturer = c = StreamCapturer(echo=not buffer_output) - c.start() - stdout = c.writefd if capture_output else None - stderr = subprocess.STDOUT if capture_output else None - self.process = subprocess.Popen(self.cmd, stdout=stdout, - stderr=stderr, env=env) - - def wait(self): - self.process.wait() - self.stdout_capturer.halt() - self.stdout = self.stdout_capturer.get_buffer() - return self.process.returncode - - def print_extra_info(self): - """Print extra information about this test run. - - If we're running in parallel and showing the concise view, this is only - called if the test group fails. Otherwise, it's called before the test - group is started. - - The base implementation does nothing, but it can be overridden by - subclasses. - """ - return - - def cleanup_process(self): - """Cleanup on exit by killing any leftover processes.""" - subp = self.process - if subp is None or (subp.poll() is not None): - return # Process doesn't exist, or is already dead. - - try: - print('Cleaning up stale PID: %d' % subp.pid) - subp.kill() - except: # (OSError, WindowsError) ? - # This is just a best effort, if we fail or the process was - # really gone, ignore it. - pass - else: - for i in range(10): - if subp.poll() is None: - time.sleep(0.1) - else: - break - - if subp.poll() is None: - # The process did not die... - print('... failed. Manual cleanup may be required.') - - def cleanup(self): - "Kill process if it's still alive, and clean up temporary directories" - self.cleanup_process() - for td in self.dirs: - td.cleanup() - - __del__ = cleanup - - -def get_js_test_dir(): - import notebook.tests as t - return os.path.join(os.path.dirname(t.__file__), '') - -def all_js_groups(): - import glob - test_dir = get_js_test_dir() - all_subdirs = glob.glob(test_dir + '[!_]*/') - return [os.path.relpath(x, test_dir) for x in all_subdirs] - -class JSController(TestController): - """Run CasperJS tests """ - - requirements = ['casperjs'] - - def __init__(self, section, xunit=True, engine='phantomjs', url=None): - """Create new test runner.""" - TestController.__init__(self) - self.engine = engine - self.section = section - self.xunit = xunit - self.url = url - # run with a base URL that would be escaped, - # to test that we don't double-escape URLs - self.base_url = '/a@b/' - self.slimer_failure = re.compile('^FAIL.*', flags=re.MULTILINE) - js_test_dir = get_js_test_dir() - includes = '--includes=' + os.path.join(js_test_dir,'util.js') - test_cases = os.path.join(js_test_dir, self.section) - self.cmd = ['casperjs', 'test', includes, test_cases, '--engine=%s' % self.engine] - - def setup(self): - self.ipydir = TemporaryDirectory() - self.config_dir = TemporaryDirectory() - self.nbdir = TemporaryDirectory() - self.home = TemporaryDirectory() - self.env = { - 'HOME': self.home.name, - 'JUPYTER_CONFIG_DIR': self.config_dir.name, - 'IPYTHONDIR': self.ipydir.name, - } - self.dirs.append(self.ipydir) - self.dirs.append(self.home) - self.dirs.append(self.config_dir) - self.dirs.append(self.nbdir) - os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub ∂ir1', u'sub ∂ir 1a'))) - os.makedirs(os.path.join(self.nbdir.name, os.path.join(u'sub ∂ir2', u'sub ∂ir 1b'))) - - if self.xunit: - self.add_xunit() - - # If a url was specified, use that for the testing. - if self.url: - try: - alive = requests.get(self.url).status_code == 200 - except: - alive = False - - if alive: - self.cmd.append("--url=%s" % self.url) - else: - raise Exception('Could not reach "%s".' % self.url) - else: - # start the ipython notebook, so we get the port number - self.server_port = 0 - self._init_server() - if self.server_port: - self.cmd.append('--url=http://localhost:%i%s' % (self.server_port, self.base_url)) - else: - # don't launch tests if the server didn't start - self.cmd = [sys.executable, '-c', 'raise SystemExit(1)'] - - def add_xunit(self): - xunit_file = os.path.abspath(self.section.replace('/','.') + '.xunit.xml') - self.cmd.append('--xunit=%s' % xunit_file) - - def launch(self, buffer_output): - # If the engine is SlimerJS, we need to buffer the output because - # SlimerJS does not support exit codes, so CasperJS always returns 0. - if self.engine == 'slimerjs' and not buffer_output: - return super().launch(capture_output=True) - - else: - return super().launch(buffer_output=buffer_output) - - def wait(self, *pargs, **kwargs): - """Wait for the JSController to finish""" - ret = super().wait(*pargs, **kwargs) - # If this is a SlimerJS controller, check the captured stdout for - # errors. Otherwise, just return the return code. - if self.engine == 'slimerjs': - stdout = bytes_to_str(self.stdout) - if ret != 0: - # This could still happen e.g. if it's stopped by SIGINT - return ret - return bool(self.slimer_failure.search(stdout)) - else: - return ret - - def print_extra_info(self): - print("Running tests with notebook directory %r" % self.nbdir.name) - - @property - def will_run(self): - should_run = all(have[a] for a in self.requirements + [self.engine]) - return should_run - - def _init_server(self): - "Start the notebook server in a separate process" - self.server_command = command = [sys.executable, - '-m', 'notebook', - '--no-browser', - '--notebook-dir', self.nbdir.name, - '--NotebookApp.token=', - '--NotebookApp.base_url=%s' % self.base_url, - ] - # ipc doesn't work on Windows, and darwin has crazy-long temp paths, - # which run afoul of ipc's maximum path length. - if sys.platform.startswith('linux'): - command.append('--KernelManager.transport=ipc') - self.stream_capturer = c = StreamCapturer() - c.start() - env = os.environ.copy() - env.update(self.env) - self.server = subprocess.Popen(command, - stdout = c.writefd, - stderr = subprocess.STDOUT, - cwd=self.nbdir.name, - env=env, - ) - with patch.dict('os.environ', {'HOME': self.home.name}): - runtime_dir = jupyter_runtime_dir() - self.server_info_file = os.path.join(runtime_dir, - 'nbserver-%i.json' % self.server.pid - ) - self._wait_for_server() - - def _wait_for_server(self): - """Wait 30 seconds for the notebook server to start""" - for i in range(300): - if self.server.poll() is not None: - return self._failed_to_start() - if os.path.exists(self.server_info_file): - try: - self._load_server_info() - except ValueError: - # If the server is halfway through writing the file, we may - # get invalid JSON; it should be ready next iteration. - pass - else: - return - time.sleep(0.1) - print("Notebook server-info file never arrived: %s" % self.server_info_file, - file=sys.stderr - ) - - def _failed_to_start(self): - """Notebook server exited prematurely""" - captured = self.stream_capturer.get_buffer().decode('utf-8', 'replace') - print("Notebook failed to start: ", file=sys.stderr) - print(self.server_command) - print(captured, file=sys.stderr) - - def _load_server_info(self): - """Notebook server started, load connection info from JSON""" - with open(self.server_info_file) as f: - info = json.load(f) - self.server_port = info['port'] - - def cleanup(self): - if hasattr(self, 'server'): - try: - self.server.terminate() - except OSError: - # already dead - pass - # wait 10s for the server to shutdown - try: - popen_wait(self.server, NOTEBOOK_SHUTDOWN_TIMEOUT) - except TimeoutExpired: - # server didn't terminate, kill it - try: - print("Failed to terminate notebook server, killing it.", - file=sys.stderr - ) - self.server.kill() - except OSError: - # already dead - pass - # wait another 10s - try: - popen_wait(self.server, NOTEBOOK_SHUTDOWN_TIMEOUT) - except TimeoutExpired: - print("Notebook server still running (%s)" % self.server_info_file, - file=sys.stderr - ) - - self.stream_capturer.halt() - TestController.cleanup(self) - - -def prepare_controllers(options): - """Returns two lists of TestController instances, those to run, and those - not to run.""" - testgroups = options.testgroups - if not testgroups: - testgroups = all_js_groups() - - engine = 'slimerjs' if options.slimerjs else 'phantomjs' - c_js = [JSController(name, xunit=options.xunit, engine=engine, url=options.url) for name in testgroups] - - controllers = c_js - to_run = [c for c in controllers if c.will_run] - not_run = [c for c in controllers if not c.will_run] - return to_run, not_run - -def do_run(controller, buffer_output=True): - """Setup and run a test controller. - - If buffer_output is True, no output is displayed, to avoid it appearing - interleaved. In this case, the caller is responsible for displaying test - output on failure. - - Returns - ------- - controller : TestController - The same controller as passed in, as a convenience for using map() type - APIs. - exitcode : int - The exit code of the test subprocess. Non-zero indicates failure. - """ - try: - try: - controller.setup() - if not buffer_output: - controller.print_extra_info() - controller.launch(buffer_output=buffer_output) - except Exception: - import traceback - traceback.print_exc() - return controller, 1 # signal failure - - exitcode = controller.wait() - return controller, exitcode - - except KeyboardInterrupt: - return controller, -signal.SIGINT - finally: - controller.cleanup() - -def report(): - """Return a string with a summary report of test-related variables.""" - inf = get_sys_info() - out = [] - def _add(name, value): - out.append((name, value)) - - _add('Python version', inf['sys_version'].replace('\n','')) - _add('sys.executable', inf['sys_executable']) - _add('Platform', inf['platform']) - - width = max(len(n) for (n,v) in out) - out = ["{:<{width}}: {}\n".format(n, v, width=width) for (n,v) in out] - - avail = [] - not_avail = [] - - for k, is_avail in have.items(): - if is_avail: - avail.append(k) - else: - not_avail.append(k) - - if avail: - out.append('\nTools and libraries available at test time:\n') - avail.sort() - out.append(' ' + ' '.join(avail)+'\n') - - if not_avail: - out.append('\nTools and libraries NOT available at test time:\n') - not_avail.sort() - out.append(' ' + ' '.join(not_avail)+'\n') - - return ''.join(out) - -def run_jstestall(options): - """Run the entire Javascript test suite. - - This function constructs TestControllers and runs them in subprocesses. - - Parameters - ---------- - - All parameters are passed as attributes of the options object. - - testgroups : list of str - Run only these sections of the test suite. If empty, run all the available - sections. - - fast : int or None - Run the test suite in parallel, using n simultaneous processes. If None - is passed, one process is used per CPU core. Default 1 (i.e. sequential) - - inc_slow : bool - Include slow tests. By default, these tests aren't run. - - slimerjs : bool - Use slimerjs if it's installed instead of phantomjs for casperjs tests. - - url : unicode - Address:port to use when running the JS tests. - - xunit : bool - Produce Xunit XML output. This is written to multiple foo.xunit.xml files. - - extra_args : list - Extra arguments to pass to the test subprocesses, e.g. '-v' - """ - to_run, not_run = prepare_controllers(options) - - def justify(ltext, rtext, width=70, fill='-'): - ltext += ' ' - rtext = (' ' + rtext).rjust(width - len(ltext), fill) - return ltext + rtext - - # Run all test runners, tracking execution time - failed = [] - t_start = time.time() - - print() - if options.fast == 1: - # This actually means sequential, i.e. with 1 job - for controller in to_run: - print('Test group:', controller.section) - sys.stdout.flush() # Show in correct order when output is piped - controller, res = do_run(controller, buffer_output=False) - if res: - failed.append(controller) - if res == -signal.SIGINT: - print("Interrupted") - break - print() - - else: - # Run tests concurrently - try: - pool = multiprocessing.pool.ThreadPool(options.fast) - for (controller, res) in pool.imap_unordered(do_run, to_run): - res_string = 'OK' if res == 0 else 'FAILED' - print(justify('Test group: ' + controller.section, res_string)) - if res: - controller.print_extra_info() - print(bytes_to_str(controller.stdout)) - failed.append(controller) - if res == -signal.SIGINT: - print("Interrupted") - break - except KeyboardInterrupt: - return - - for controller in not_run: - print(justify('Test group: ' + controller.section, 'NOT RUN')) - - t_end = time.time() - t_tests = t_end - t_start - nrunners = len(to_run) - nfail = len(failed) - # summarize results - print('_'*70) - print('Test suite completed for system with the following information:') - print(report()) - took = "Took %.3fs." % t_tests - print('Status: ', end='') - if not failed: - print('OK (%d test groups).' % nrunners, took) - else: - # If anything went wrong, point out what command to rerun manually to - # see the actual errors and individual summary - failed_sections = [c.section for c in failed] - print('ERROR - {} out of {} test groups failed ({}).'.format(nfail, - nrunners, ', '.join(failed_sections)), took) - print() - print('You may wish to rerun these, with:') - print(' python -m notebook.jstest', *failed_sections) - print() - - if failed: - # Ensure that our exit code indicates failure - sys.exit(1) - -argparser = argparse.ArgumentParser(description='Run Jupyter Notebook Javascript tests') -argparser.add_argument('testgroups', nargs='*', - help='Run specified groups of tests. If omitted, run ' - 'all tests.') -argparser.add_argument('--slimerjs', action='store_true', - help="Use slimerjs if it's installed instead of phantomjs for casperjs tests.") -argparser.add_argument('--url', help="URL to use for the JS tests.") -argparser.add_argument('-j', '--fast', nargs='?', const=None, default=1, type=int, - help='Run test sections in parallel. This starts as many ' - 'processes as you have cores, or you can specify a number.') -argparser.add_argument('--xunit', action='store_true', - help='Produce Xunit XML results') -argparser.add_argument('--subproc-streams', default='capture', - help="What to do with stdout/stderr from subprocesses. " - "'capture' (default), 'show' and 'discard' are the options.") - -def default_options(): - """Get an argparse Namespace object with the default arguments, to pass to - :func:`run_iptestall`. - """ - options = argparser.parse_args([]) - options.extra_args = [] - return options - -def main(): - try: - ix = sys.argv.index('--') - except ValueError: - to_parse = sys.argv[1:] - extra_args = [] - else: - to_parse = sys.argv[1:ix] - extra_args = sys.argv[ix+1:] - - options = argparser.parse_args(to_parse) - options.extra_args = extra_args - - run_jstestall(options) - - -if __name__ == '__main__': - main() diff --git a/notebook/kernelspecs/__init__.py b/notebook/kernelspecs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/kernelspecs/handlers.py b/notebook/kernelspecs/handlers.py deleted file mode 100644 index be768b5ab..000000000 --- a/notebook/kernelspecs/handlers.py +++ /dev/null @@ -1,28 +0,0 @@ -from tornado import web -from ..base.handlers import IPythonHandler -from ..services.kernelspecs.handlers import kernel_name_regex - -class KernelSpecResourceHandler(web.StaticFileHandler, IPythonHandler): - SUPPORTED_METHODS = ('GET', 'HEAD') - - def initialize(self): - web.StaticFileHandler.initialize(self, path='') - - @web.authenticated - def get(self, kernel_name, path, include_body=True): - ksm = self.kernel_spec_manager - try: - self.root = ksm.get_kernel_spec(kernel_name).resource_dir - except KeyError as e: - raise web.HTTPError(404, - u'Kernel spec %s not found' % kernel_name) from e - self.log.debug("Serving kernel resource from: %s", self.root) - return web.StaticFileHandler.get(self, path, include_body=include_body) - - @web.authenticated - def head(self, kernel_name, path): - return self.get(kernel_name, path, include_body=False) - -default_handlers = [ - (r"/kernelspecs/%s/(?P.*)" % kernel_name_regex, KernelSpecResourceHandler), -] \ No newline at end of file diff --git a/notebook/log.py b/notebook/log.py deleted file mode 100644 index eb246bc40..000000000 --- a/notebook/log.py +++ /dev/null @@ -1,56 +0,0 @@ -#----------------------------------------------------------------------------- -# Copyright (c) Jupyter Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file LICENSE, distributed as part of this software. -#----------------------------------------------------------------------------- - -import json -from tornado.log import access_log -from .prometheus.log_functions import prometheus_log_method - - -def log_request(handler, log=access_log, log_json=False): - """log a bit more information about each request than tornado's default - - - move static file get success to debug-level (reduces noise) - - get proxied IP instead of proxy IP - - log referer for redirect and failed requests - - log user-agent for failed requests - """ - status = handler.get_status() - request = handler.request - if status < 300 or status == 304: - # Successes (or 304 FOUND) are debug-level - log_method = log.debug - elif status < 400: - log_method = log.info - elif status < 500: - log_method = log.warning - else: - log_method = log.error - - request_time = 1000.0 * request.request_time() - ns = dict( - status=status, - method=request.method, - ip=request.remote_ip, - uri=request.uri, - request_time=float('%.2f' % request_time), - ) - msg = "{status} {method} {uri} ({ip}) {request_time:f}ms" - if status >= 400: - # log bad referers - ns['referer'] = request.headers.get('Referer', 'None') - msg = msg + ' referer={referer}' - if status >= 500 and status != 502: - # log all headers if it caused an error - if log_json: - log_method("", extra=dict(props=dict(request.headers))) - else: - log_method(json.dumps(dict(request.headers), indent=2)) - if log_json: - log_method("", extra=dict(props=ns)) - else: - log_method(msg.format(**ns)) - prometheus_log_method(handler) diff --git a/notebook/nbconvert/__init__.py b/notebook/nbconvert/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/nbconvert/handlers.py b/notebook/nbconvert/handlers.py deleted file mode 100644 index 24a3f093f..000000000 --- a/notebook/nbconvert/handlers.py +++ /dev/null @@ -1,200 +0,0 @@ -"""Tornado handlers for nbconvert.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import io -import os -import zipfile - -from tornado import gen, web, escape -from tornado.log import app_log - -from ..base.handlers import ( - IPythonHandler, FilesRedirectHandler, - path_regex, -) -from ..utils import maybe_future -from nbformat import from_dict - -from ipython_genutils.py3compat import cast_bytes -from ipython_genutils import text - -def find_resource_files(output_files_dir): - files = [] - for dirpath, dirnames, filenames in os.walk(output_files_dir): - files.extend([os.path.join(dirpath, f) for f in filenames]) - return files - -def respond_zip(handler, name, output, resources): - """Zip up the output and resource files and respond with the zip file. - - Returns True if it has served a zip file, False if there are no resource - files, in which case we serve the plain output file. - """ - # Check if we have resource files we need to zip - output_files = resources.get('outputs', None) - if not output_files: - return False - - # Headers - zip_filename = os.path.splitext(name)[0] + '.zip' - handler.set_attachment_header(zip_filename) - handler.set_header('Content-Type', 'application/zip') - handler.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') - - # Prepare the zip file - buffer = io.BytesIO() - zipf = zipfile.ZipFile(buffer, mode='w', compression=zipfile.ZIP_DEFLATED) - output_filename = os.path.splitext(name)[0] + resources['output_extension'] - zipf.writestr(output_filename, cast_bytes(output, 'utf-8')) - for filename, data in output_files.items(): - zipf.writestr(os.path.basename(filename), data) - zipf.close() - - handler.finish(buffer.getvalue()) - return True - -def get_exporter(format, **kwargs): - """get an exporter, raising appropriate errors""" - # if this fails, will raise 500 - try: - from nbconvert.exporters.base import get_exporter - except ImportError as e: - raise web.HTTPError(500, "Could not import nbconvert: %s" % e) from e - - try: - Exporter = get_exporter(format) - except KeyError as e: - # should this be 400? - raise web.HTTPError(404, u"No exporter for format: %s" % format) from e - - try: - return Exporter(**kwargs) - except Exception as e: - app_log.exception("Could not construct Exporter: %s", Exporter) - raise web.HTTPError(500, "Could not construct Exporter: %s" % e) from e - -class NbconvertFileHandler(IPythonHandler): - - SUPPORTED_METHODS = ('GET',) - - @property - def content_security_policy(self): - # In case we're serving HTML/SVG, confine any Javascript to a unique - # origin so it can't interact with the notebook server. - return super().content_security_policy + "; sandbox allow-scripts" - - @web.authenticated - @gen.coroutine - def get(self, format, path): - - exporter = get_exporter(format, config=self.config, log=self.log) - - path = path.strip('/') - # If the notebook relates to a real file (default contents manager), - # give its path to nbconvert. - if hasattr(self.contents_manager, '_get_os_path'): - os_path = self.contents_manager._get_os_path(path) - ext_resources_dir, basename = os.path.split(os_path) - else: - ext_resources_dir = None - - model = yield maybe_future(self.contents_manager.get(path=path)) - name = model['name'] - if model['type'] != 'notebook': - # not a notebook, redirect to files - return FilesRedirectHandler.redirect_to_files(self, path) - - nb = model['content'] - - self.set_header('Last-Modified', model['last_modified']) - - # create resources dictionary - mod_date = model['last_modified'].strftime(text.date_format) - nb_title = os.path.splitext(name)[0] - - resource_dict = { - "metadata": { - "name": nb_title, - "modified_date": mod_date - }, - "config_dir": self.application.settings['config_dir'] - } - - if ext_resources_dir: - resource_dict['metadata']['path'] = ext_resources_dir - - try: - output, resources = exporter.from_notebook_node( - nb, - resources=resource_dict - ) - except Exception as e: - self.log.exception("nbconvert failed: %s", e) - raise web.HTTPError(500, "nbconvert failed: %s" % e) from e - - if respond_zip(self, name, output, resources): - return - - # Force download if requested - if self.get_argument('download', 'false').lower() == 'true': - filename = os.path.splitext(name)[0] + resources['output_extension'] - self.set_attachment_header(filename) - - # MIME type - if exporter.output_mimetype: - self.set_header('Content-Type', - '%s; charset=utf-8' % exporter.output_mimetype) - - self.set_header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') - self.finish(output) - -class NbconvertPostHandler(IPythonHandler): - SUPPORTED_METHODS = ('POST',) - - @property - def content_security_policy(self): - # In case we're serving HTML/SVG, confine any Javascript to a unique - # origin so it can't interact with the notebook server. - return super().content_security_policy + "; sandbox allow-scripts" - - @web.authenticated - def post(self, format): - exporter = get_exporter(format, config=self.config) - - model = self.get_json_body() - name = model.get('name', 'notebook.ipynb') - nbnode = from_dict(model['content']) - - try: - output, resources = exporter.from_notebook_node(nbnode, resources={ - "metadata": {"name": name[:name.rfind('.')],}, - "config_dir": self.application.settings['config_dir'], - }) - except Exception as e: - raise web.HTTPError(500, "nbconvert failed: %s" % e) from e - - if respond_zip(self, name, output, resources): - return - - # MIME type - if exporter.output_mimetype: - self.set_header('Content-Type', - '%s; charset=utf-8' % exporter.output_mimetype) - - self.finish(output) - - -#----------------------------------------------------------------------------- -# URL to handler mappings -#----------------------------------------------------------------------------- - -_format_regex = r"(?P\w+)" - - -default_handlers = [ - (r"/nbconvert/%s" % _format_regex, NbconvertPostHandler), - (r"/nbconvert/%s%s" % (_format_regex, path_regex), - NbconvertFileHandler), -] diff --git a/notebook/nbconvert/tests/__init__.py b/notebook/nbconvert/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/nbconvert/tests/test_nbconvert_handlers.py b/notebook/nbconvert/tests/test_nbconvert_handlers.py deleted file mode 100644 index e5af13c0c..000000000 --- a/notebook/nbconvert/tests/test_nbconvert_handlers.py +++ /dev/null @@ -1,158 +0,0 @@ -import io -import json -import os -from os.path import join as pjoin -import shutil - -import requests -import pytest -from notebook.utils import url_path_join -from notebook.tests.launchnotebook import NotebookTestBase, assert_http_error -from nbformat import write -from nbformat.v4 import ( - new_notebook, new_markdown_cell, new_code_cell, new_output, -) - -from ipython_genutils.testing.decorators import onlyif_cmds_exist - -from base64 import encodebytes - - -def cmd_exists(cmd): - """Check is a command exists.""" - if shutil.which(cmd) is None: - return False - return True - - -class NbconvertAPI(object): - """Wrapper for nbconvert API calls.""" - def __init__(self, request): - self.request = request - - def _req(self, verb, path, body=None, params=None): - response = self.request(verb, - url_path_join('nbconvert', path), - data=body, params=params, - ) - response.raise_for_status() - return response - - def from_file(self, format, path, name, download=False): - return self._req('GET', url_path_join(format, path, name), - params={'download':download}) - - def from_post(self, format, nbmodel): - body = json.dumps(nbmodel) - return self._req('POST', format, body) - - def list_formats(self): - return self._req('GET', '') - -png_green_pixel = encodebytes(b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00' -b'\x00\x00\x01\x00\x00x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDAT' -b'\x08\xd7c\x90\xfb\xcf\x00\x00\x02\\\x01\x1e.~d\x87\x00\x00\x00\x00IEND\xaeB`\x82' -).decode('ascii') - -class APITest(NotebookTestBase): - def setUp(self): - nbdir = self.notebook_dir - - if not os.path.isdir(pjoin(nbdir, 'foo')): - subdir = pjoin(nbdir, 'foo') - - os.mkdir(subdir) - - # Make sure that we clean this up when we're done. - # By using addCleanup this will happen correctly even if we fail - # later in setUp. - @self.addCleanup - def cleanup_dir(): - shutil.rmtree(subdir, ignore_errors=True) - - nb = new_notebook() - - nb.cells.append(new_markdown_cell(u'Created by test ³')) - cc1 = new_code_cell(source=u'print(2*6)') - cc1.outputs.append(new_output(output_type="stream", text=u'12')) - cc1.outputs.append(new_output(output_type="execute_result", - data={'image/png' : png_green_pixel}, - execution_count=1, - )) - nb.cells.append(cc1) - - with io.open(pjoin(nbdir, 'foo', 'testnb.ipynb'), 'w', - encoding='utf-8') as f: - write(nb, f, version=4) - - self.nbconvert_api = NbconvertAPI(self.request) - - @pytest.mark.skipif( - not cmd_exists('pandoc'), - reason="Pandoc wasn't found. Skipping this test." - ) - def test_from_file(self): - r = self.nbconvert_api.from_file('html', 'foo', 'testnb.ipynb') - self.assertEqual(r.status_code, 200) - self.assertIn(u'text/html', r.headers['Content-Type']) - self.assertIn(u'Created by test', r.text) - self.assertIn(u'print', r.text) - - r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb') - self.assertIn(u'text/x-python', r.headers['Content-Type']) - self.assertIn(u'print(2*6)', r.text) - - @pytest.mark.skipif( - not cmd_exists('pandoc'), - reason="Pandoc wasn't found. Skipping this test." - ) - def test_from_file_404(self): - with assert_http_error(404): - self.nbconvert_api.from_file('html', 'foo', 'thisdoesntexist.ipynb') - - @pytest.mark.skipif( - not cmd_exists('pandoc'), - reason="Pandoc wasn't found. Skipping this test." - ) - def test_from_file_download(self): - r = self.nbconvert_api.from_file('python', 'foo', 'testnb.ipynb', download=True) - content_disposition = r.headers['Content-Disposition'] - self.assertIn('attachment', content_disposition) - self.assertIn('testnb.py', content_disposition) - - @pytest.mark.skipif( - not cmd_exists('pandoc'), - reason="Pandoc wasn't found. Skipping this test." - ) - def test_from_file_zip(self): - r = self.nbconvert_api.from_file('latex', 'foo', 'testnb.ipynb', download=True) - self.assertIn(u'application/zip', r.headers['Content-Type']) - self.assertIn(u'.zip', r.headers['Content-Disposition']) - - @pytest.mark.skipif( - not cmd_exists('pandoc'), - reason="Pandoc wasn't found. Skipping this test." - ) - def test_from_post(self): - nbmodel = self.request('GET', 'api/contents/foo/testnb.ipynb').json() - - r = self.nbconvert_api.from_post(format='html', nbmodel=nbmodel) - self.assertEqual(r.status_code, 200) - self.assertIn(u'text/html', r.headers['Content-Type']) - self.assertIn(u'Created by test', r.text) - self.assertIn(u'print', r.text) - - r = self.nbconvert_api.from_post(format='python', nbmodel=nbmodel) - self.assertIn(u'text/x-python', r.headers['Content-Type']) - self.assertIn(u'print(2*6)', r.text) - - @pytest.mark.skipif( - not cmd_exists('pandoc'), - reason="Pandoc wasn't found. Skipping this test." - ) - def test_from_post_zip(self): - nbmodel = self.request('GET', 'api/contents/foo/testnb.ipynb').json() - - r = self.nbconvert_api.from_post(format='latex', nbmodel=nbmodel) - self.assertIn(u'application/zip', r.headers['Content-Type']) - self.assertIn(u'.zip', r.headers['Content-Disposition']) diff --git a/notebook/nbextensions.py b/notebook/nbextensions.py deleted file mode 100644 index aac752cce..000000000 --- a/notebook/nbextensions.py +++ /dev/null @@ -1,1124 +0,0 @@ -"""Utilities for installing Javascript extensions for the notebook""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import shutil -import sys -import tarfile -import zipfile -from os.path import basename, join as pjoin, normpath - -from urllib.parse import urlparse -from urllib.request import urlretrieve -from jupyter_core.paths import ( - jupyter_data_dir, jupyter_config_path, jupyter_path, - SYSTEM_JUPYTER_PATH, ENV_JUPYTER_PATH, -) -from jupyter_core.utils import ensure_dir_exists -from ipython_genutils.py3compat import string_types, cast_unicode_py2 -from ipython_genutils.tempdir import TemporaryDirectory -from ._version import __version__ -from .config_manager import BaseJSONConfigManager - -from traitlets.utils.importstring import import_item - -DEPRECATED_ARGUMENT = object() - -NBCONFIG_SECTIONS = ['common', 'notebook', 'tree', 'edit', 'terminal'] - - -#------------------------------------------------------------------------------ -# Public API -#------------------------------------------------------------------------------ - -def check_nbextension(files, user=False, prefix=None, nbextensions_dir=None, sys_prefix=False): - """Check whether nbextension files have been installed - - Returns True if all files are found, False if any are missing. - - Parameters - ---------- - - files : list(paths) - a list of relative paths within nbextensions. - user : bool [default: False] - Whether to check the user's .jupyter/nbextensions directory. - Otherwise check a system-wide install (e.g. /usr/local/share/jupyter/nbextensions). - prefix : str [optional] - Specify install prefix, if it should differ from default (e.g. /usr/local). - Will check prefix/share/jupyter/nbextensions - nbextensions_dir : str [optional] - Specify absolute path of nbextensions directory explicitly. - sys_prefix : bool [default: False] - Install into the sys.prefix, i.e. environment - """ - nbext = _get_nbextension_dir(user=user, sys_prefix=sys_prefix, prefix=prefix, nbextensions_dir=nbextensions_dir) - # make sure nbextensions dir exists - if not os.path.exists(nbext): - return False - - if isinstance(files, string_types): - # one file given, turn it into a list - files = [files] - - return all(os.path.exists(pjoin(nbext, f)) for f in files) - - -def install_nbextension(path, overwrite=False, symlink=False, - user=False, prefix=None, nbextensions_dir=None, - destination=None, verbose=DEPRECATED_ARGUMENT, - logger=None, sys_prefix=False - ): - """Install a Javascript extension for the notebook - - Stages files and/or directories into the nbextensions directory. - By default, this compares modification time, and only stages files that need updating. - If `overwrite` is specified, matching files are purged before proceeding. - - Parameters - ---------- - - path : path to file, directory, zip or tarball archive, or URL to install - By default, the file will be installed with its base name, so '/path/to/foo' - will install to 'nbextensions/foo'. See the destination argument below to change this. - Archives (zip or tarballs) will be extracted into the nbextensions directory. - overwrite : bool [default: False] - If True, always install the files, regardless of what may already be installed. - symlink : bool [default: False] - If True, create a symlink in nbextensions, rather than copying files. - Not allowed with URLs or archives. Windows support for symlinks requires - Vista or above, Python 3, and a permission bit which only admin users - have by default, so don't rely on it. - user : bool [default: False] - Whether to install to the user's nbextensions directory. - Otherwise do a system-wide install (e.g. /usr/local/share/jupyter/nbextensions). - prefix : str [optional] - Specify install prefix, if it should differ from default (e.g. /usr/local). - Will install to ``/share/jupyter/nbextensions`` - nbextensions_dir : str [optional] - Specify absolute path of nbextensions directory explicitly. - destination : str [optional] - name the nbextension is installed to. For example, if destination is 'foo', then - the source file will be installed to 'nbextensions/foo', regardless of the source name. - This cannot be specified if an archive is given as the source. - logger : Jupyter logger [optional] - Logger instance to use - """ - if verbose != DEPRECATED_ARGUMENT: - import warnings - warnings.warn("`install_nbextension`'s `verbose` parameter is deprecated, it will have no effects and will be removed in Notebook 5.0", DeprecationWarning) - - # the actual path to which we eventually installed - full_dest = None - - nbext = _get_nbextension_dir(user=user, sys_prefix=sys_prefix, prefix=prefix, nbextensions_dir=nbextensions_dir) - # make sure nbextensions dir exists - ensure_dir_exists(nbext) - - # forcing symlink parameter to False if os.symlink does not exist (e.g., on Windows machines running python 2) - if not hasattr(os, 'symlink'): - symlink = False - - if isinstance(path, (list, tuple)): - raise TypeError("path must be a string pointing to a single extension to install; call this function multiple times to install multiple extensions") - - path = cast_unicode_py2(path) - - if path.startswith(('https://', 'http://')): - if symlink: - raise ValueError("Cannot symlink from URLs") - # Given a URL, download it - with TemporaryDirectory() as td: - filename = urlparse(path).path.split('/')[-1] - local_path = os.path.join(td, filename) - if logger: - logger.info("Downloading: %s -> %s" % (path, local_path)) - urlretrieve(path, local_path) - # now install from the local copy - full_dest = install_nbextension(local_path, overwrite=overwrite, symlink=symlink, - nbextensions_dir=nbext, destination=destination, logger=logger) - elif path.endswith('.zip') or _safe_is_tarfile(path): - if symlink: - raise ValueError("Cannot symlink from archives") - if destination: - raise ValueError("Cannot give destination for archives") - if logger: - logger.info("Extracting: %s -> %s" % (path, nbext)) - - if path.endswith('.zip'): - archive = zipfile.ZipFile(path) - elif _safe_is_tarfile(path): - archive = tarfile.open(path) - archive.extractall(nbext) - archive.close() - # TODO: what to do here - full_dest = None - else: - if not destination: - destination = basename(normpath(path)) - destination = cast_unicode_py2(destination) - full_dest = normpath(pjoin(nbext, destination)) - if overwrite and os.path.lexists(full_dest): - if logger: - logger.info("Removing: %s" % full_dest) - if os.path.isdir(full_dest) and not os.path.islink(full_dest): - shutil.rmtree(full_dest) - else: - os.remove(full_dest) - - if symlink: - path = os.path.abspath(path) - if not os.path.exists(full_dest): - if logger: - logger.info("Symlinking: %s -> %s" % (full_dest, path)) - os.symlink(path, full_dest) - elif os.path.isdir(path): - path = pjoin(os.path.abspath(path), '') # end in path separator - for parent, dirs, files in os.walk(path): - dest_dir = pjoin(full_dest, parent[len(path):]) - if not os.path.exists(dest_dir): - if logger: - logger.info("Making directory: %s" % dest_dir) - os.makedirs(dest_dir) - for file_name in files: - src = pjoin(parent, file_name) - dest_file = pjoin(dest_dir, file_name) - _maybe_copy(src, dest_file, logger=logger) - else: - src = path - _maybe_copy(src, full_dest, logger=logger) - - return full_dest - - -def install_nbextension_python(module, overwrite=False, symlink=False, - user=False, sys_prefix=False, prefix=None, nbextensions_dir=None, logger=None): - """Install an nbextension bundled in a Python package. - - Returns a list of installed/updated directories. - - See install_nbextension for parameter information.""" - m, nbexts = _get_nbextension_metadata(module) - base_path = os.path.split(m.__file__)[0] - - full_dests = [] - - for nbext in nbexts: - src = os.path.join(base_path, nbext['src']) - dest = nbext['dest'] - - if logger: - logger.info("Installing %s -> %s" % (src, dest)) - full_dest = install_nbextension( - src, overwrite=overwrite, symlink=symlink, - user=user, sys_prefix=sys_prefix, prefix=prefix, nbextensions_dir=nbextensions_dir, - destination=dest, logger=logger - ) - validate_nbextension_python(nbext, full_dest, logger) - full_dests.append(full_dest) - - return full_dests - - -def uninstall_nbextension(dest, require=None, user=False, sys_prefix=False, prefix=None, - nbextensions_dir=None, logger=None): - """Uninstall a Javascript extension of the notebook - - Removes staged files and/or directories in the nbextensions directory and - removes the extension from the frontend config. - - Parameters - ---------- - - dest : str - path to file, directory, zip or tarball archive, or URL to install - name the nbextension is installed to. For example, if destination is 'foo', then - the source file will be installed to 'nbextensions/foo', regardless of the source name. - This cannot be specified if an archive is given as the source. - require : str [optional] - require.js path used to load the extension. - If specified, frontend config loading extension will be removed. - user : bool [default: False] - Whether to install to the user's nbextensions directory. - Otherwise do a system-wide install (e.g. /usr/local/share/jupyter/nbextensions). - prefix : str [optional] - Specify install prefix, if it should differ from default (e.g. /usr/local). - Will install to ``/share/jupyter/nbextensions`` - nbextensions_dir : str [optional] - Specify absolute path of nbextensions directory explicitly. - logger : Jupyter logger [optional] - Logger instance to use - """ - nbext = _get_nbextension_dir(user=user, sys_prefix=sys_prefix, prefix=prefix, nbextensions_dir=nbextensions_dir) - dest = cast_unicode_py2(dest) - full_dest = pjoin(nbext, dest) - if os.path.lexists(full_dest): - if logger: - logger.info("Removing: %s" % full_dest) - if os.path.isdir(full_dest) and not os.path.islink(full_dest): - shutil.rmtree(full_dest) - else: - os.remove(full_dest) - - # Look through all of the config sections making sure that the nbextension - # doesn't exist. - config_dir = os.path.join(_get_config_dir(user=user, sys_prefix=sys_prefix), 'nbconfig') - cm = BaseJSONConfigManager(config_dir=config_dir) - if require: - for section in NBCONFIG_SECTIONS: - cm.update(section, {"load_extensions": {require: None}}) - - -def _find_uninstall_nbextension(filename, logger=None): - """Remove nbextension files from the first location they are found. - - Returns True if files were removed, False otherwise. - """ - filename = cast_unicode_py2(filename) - for nbext in jupyter_path('nbextensions'): - path = pjoin(nbext, filename) - if os.path.lexists(path): - if logger: - logger.info("Removing: %s" % path) - if os.path.isdir(path) and not os.path.islink(path): - shutil.rmtree(path) - else: - os.remove(path) - return True - - return False - - -def uninstall_nbextension_python(module, - user=False, sys_prefix=False, prefix=None, nbextensions_dir=None, - logger=None): - """Uninstall an nbextension bundled in a Python package. - - See parameters of `install_nbextension_python` - """ - m, nbexts = _get_nbextension_metadata(module) - for nbext in nbexts: - dest = nbext['dest'] - require = nbext['require'] - if logger: - logger.info("Uninstalling {} {}".format(dest, require)) - uninstall_nbextension(dest, require, user=user, sys_prefix=sys_prefix, - prefix=prefix, nbextensions_dir=nbextensions_dir, logger=logger) - - -def _set_nbextension_state(section, require, state, - user=True, sys_prefix=False, logger=None): - """Set whether the section's frontend should require the named nbextension - - Returns True if the final state is the one requested. - - Parameters - ---------- - section : string - The section of the server to change, one of NBCONFIG_SECTIONS - require : string - An importable AMD module inside the nbextensions static path - state : bool - The state in which to leave the extension - user : bool [default: True] - Whether to update the user's .jupyter/nbextensions directory - sys_prefix : bool [default: False] - Whether to update the sys.prefix, i.e. environment. Will override - `user`. - logger : Jupyter logger [optional] - Logger instance to use - """ - user = False if sys_prefix else user - config_dir = os.path.join( - _get_config_dir(user=user, sys_prefix=sys_prefix), 'nbconfig') - cm = BaseJSONConfigManager(config_dir=config_dir) - if logger: - logger.info("{} {} extension {}...".format( - "Enabling" if state else "Disabling", - section, - require - )) - cm.update(section, {"load_extensions": {require: state}}) - - validate_nbextension(require, logger=logger) - - return cm.get(section).get(require) == state - - -def _set_nbextension_state_python(state, module, user, sys_prefix, - logger=None): - """Enable or disable some nbextensions stored in a Python package - - Returns a list of whether the state was achieved (i.e. changed, or was - already right) - - Parameters - ---------- - - state : Bool - Whether the extensions should be enabled - module : str - Importable Python module exposing the - magic-named `_jupyter_nbextension_paths` function - user : bool - Whether to enable in the user's nbextensions directory. - sys_prefix : bool - Enable/disable in the sys.prefix, i.e. environment - logger : Jupyter logger [optional] - Logger instance to use - """ - m, nbexts = _get_nbextension_metadata(module) - return [_set_nbextension_state(section=nbext["section"], - require=nbext["require"], - state=state, - user=user, sys_prefix=sys_prefix, - logger=logger) - for nbext in nbexts] - - -def enable_nbextension(section, require, user=True, sys_prefix=False, - logger=None): - """Enable a named nbextension - - Returns True if the final state is the one requested. - - Parameters - ---------- - - section : string - The section of the server to change, one of NBCONFIG_SECTIONS - require : string - An importable AMD module inside the nbextensions static path - user : bool [default: True] - Whether to enable in the user's nbextensions directory. - sys_prefix : bool [default: False] - Whether to enable in the sys.prefix, i.e. environment. Will override - `user` - logger : Jupyter logger [optional] - Logger instance to use - """ - return _set_nbextension_state(section=section, require=require, - state=True, - user=user, sys_prefix=sys_prefix, - logger=logger) - - -def disable_nbextension(section, require, user=True, sys_prefix=False, - logger=None): - """Disable a named nbextension - - Returns True if the final state is the one requested. - - Parameters - ---------- - - section : string - The section of the server to change, one of NBCONFIG_SECTIONS - require : string - An importable AMD module inside the nbextensions static path - user : bool [default: True] - Whether to enable in the user's nbextensions directory. - sys_prefix : bool [default: False] - Whether to enable in the sys.prefix, i.e. environment. Will override - `user`. - logger : Jupyter logger [optional] - Logger instance to use - """ - return _set_nbextension_state(section=section, require=require, - state=False, - user=user, sys_prefix=sys_prefix, - logger=logger) - - -def _find_disable_nbextension(section, require, logger=None): - """Disable an nbextension from the first config location where it is enabled. - - Returns True if it changed any config, False otherwise. - """ - for config_dir in jupyter_config_path(): - cm = BaseJSONConfigManager( - config_dir=os.path.join(config_dir, 'nbconfig')) - d = cm.get(section) - if d.get('load_extensions', {}).get(require, None): - if logger: - logger.info("Disabling %s extension in %s", require, config_dir) - cm.update(section, {'load_extensions': {require: None}}) - return True - - return False - - -def enable_nbextension_python(module, user=True, sys_prefix=False, - logger=None): - """Enable some nbextensions associated with a Python module. - - Returns a list of whether the state was achieved (i.e. changed, or was - already right) - - Parameters - ---------- - - module : str - Importable Python module exposing the - magic-named `_jupyter_nbextension_paths` function - user : bool [default: True] - Whether to enable in the user's nbextensions directory. - sys_prefix : bool [default: False] - Whether to enable in the sys.prefix, i.e. environment. Will override - `user` - logger : Jupyter logger [optional] - Logger instance to use - """ - return _set_nbextension_state_python(True, module, user, sys_prefix, - logger=logger) - - -def disable_nbextension_python(module, user=True, sys_prefix=False, - logger=None): - """Disable some nbextensions associated with a Python module. - - Returns True if the final state is the one requested. - - Parameters - ---------- - - module : str - Importable Python module exposing the - magic-named `_jupyter_nbextension_paths` function - user : bool [default: True] - Whether to enable in the user's nbextensions directory. - sys_prefix : bool [default: False] - Whether to enable in the sys.prefix, i.e. environment - logger : Jupyter logger [optional] - Logger instance to use - """ - return _set_nbextension_state_python(False, module, user, sys_prefix, - logger=logger) - - -def validate_nbextension(require, logger=None): - """Validate a named nbextension. - - Looks across all of the nbextension directories. - - Returns a list of warnings. - - require : str - require.js path used to load the extension - logger : Jupyter logger [optional] - Logger instance to use - """ - warnings = [] - infos = [] - - js_exists = False - for exts in jupyter_path('nbextensions'): - # Does the Javascript entrypoint actually exist on disk? - js = u"{}.js".format(os.path.join(exts, *require.split("/"))) - js_exists = os.path.exists(js) - if js_exists: - break - - require_tmpl = u" - require? {} {}" - if js_exists: - infos.append(require_tmpl.format(GREEN_OK, require)) - else: - warnings.append(require_tmpl.format(RED_X, require)) - - if logger: - if warnings: - logger.warning(u" - Validating: problems found:") - for msg in warnings: - logger.warning(msg) - for msg in infos: - logger.info(msg) - else: - logger.info(u" - Validating: {}".format(GREEN_OK)) - - return warnings - - -def validate_nbextension_python(spec, full_dest, logger=None): - """Assess the health of an installed nbextension - - Returns a list of warnings. - - Parameters - ---------- - - spec : dict - A single entry of _jupyter_nbextension_paths(): - [{ - 'section': 'notebook', - 'src': 'mockextension', - 'dest': '_mockdestination', - 'require': '_mockdestination/index' - }] - full_dest : str - The on-disk location of the installed nbextension: this should end - with `nbextensions/` - logger : Jupyter logger [optional] - Logger instance to use - """ - infos = [] - warnings = [] - - section = spec.get("section", None) - if section in NBCONFIG_SECTIONS: - infos.append(u" {} section: {}".format(GREEN_OK, section)) - else: - warnings.append(u" {} section: {}".format(RED_X, section)) - - require = spec.get("require", None) - if require is not None: - require_path = os.path.join( - full_dest[0:-len(spec["dest"])], - u"{}.js".format(require)) - if os.path.exists(require_path): - infos.append(u" {} require: {}".format(GREEN_OK, require_path)) - else: - warnings.append(u" {} require: {}".format(RED_X, require_path)) - - if logger: - if warnings: - logger.warning("- Validating: problems found:") - for msg in warnings: - logger.warning(msg) - for msg in infos: - logger.info(msg) - logger.warning(u"Full spec: {}".format(spec)) - else: - logger.info(u"- Validating: {}".format(GREEN_OK)) - - return warnings - - -#---------------------------------------------------------------------- -# Applications -#---------------------------------------------------------------------- - -from .extensions import ( - BaseExtensionApp, _get_config_dir, GREEN_ENABLED, RED_DISABLED, GREEN_OK, RED_X, - ArgumentConflict, _base_aliases, _base_flags, -) -from traitlets import Bool, Unicode - -flags = {} -flags.update(_base_flags) -flags.update({ - "overwrite" : ({ - "InstallNBExtensionApp" : { - "overwrite" : True, - }}, "Force overwrite of existing files" - ), - "symlink" : ({ - "InstallNBExtensionApp" : { - "symlink" : True, - }}, "Create symlink instead of copying files" - ), -}) - -flags['s'] = flags['symlink'] - -aliases = {} -aliases.update(_base_aliases) -aliases.update({ - "prefix" : "InstallNBExtensionApp.prefix", - "nbextensions" : "InstallNBExtensionApp.nbextensions_dir", - "destination" : "InstallNBExtensionApp.destination", -}) - -class InstallNBExtensionApp(BaseExtensionApp): - """Entry point for installing notebook extensions""" - description = """Install Jupyter notebook extensions - - Usage - - jupyter nbextension install path|url [--user|--sys-prefix] - - This copies a file or a folder into the Jupyter nbextensions directory. - If a URL is given, it will be downloaded. - If an archive is given, it will be extracted into nbextensions. - If the requested files are already up to date, no action is taken - unless --overwrite is specified. - """ - - examples = """ - jupyter nbextension install /path/to/myextension - """ - aliases = aliases - flags = flags - - overwrite = Bool(False, config=True, help="Force overwrite of existing files") - symlink = Bool(False, config=True, help="Create symlinks instead of copying files") - - prefix = Unicode('', config=True, help="Installation prefix") - nbextensions_dir = Unicode('', config=True, - help="Full path to nbextensions dir (probably use prefix or user)") - destination = Unicode('', config=True, help="Destination for the copy or symlink") - - def _config_file_name_default(self): - """The default config file name.""" - return 'jupyter_notebook_config' - - def install_extensions(self): - """Perform the installation of nbextension(s)""" - if len(self.extra_args)>1: - raise ValueError("Only one nbextension allowed at a time. " - "Call multiple times to install multiple extensions.") - - if self.python: - install = install_nbextension_python - kwargs = {} - else: - install = install_nbextension - kwargs = {'destination': self.destination} - - full_dests = install(self.extra_args[0], - overwrite=self.overwrite, - symlink=self.symlink, - user=self.user, - sys_prefix=self.sys_prefix, - prefix=self.prefix, - nbextensions_dir=self.nbextensions_dir, - logger=self.log, - **kwargs - ) - - if full_dests: - self.log.info( - u"\nTo initialize this nbextension in the browser every time" - " the notebook (or other app) loads:\n\n" - " jupyter nbextension enable {}{}{}{}\n".format( - self.extra_args[0] if self.python else "", - " --user" if self.user else "", - " --py" if self.python else "", - " --sys-prefix" if self.sys_prefix else "" - ) - ) - - def start(self): - """Perform the App's function as configured""" - if not self.extra_args: - sys.exit('Please specify an nbextension to install') - else: - try: - self.install_extensions() - except ArgumentConflict as e: - sys.exit(str(e)) - - -class UninstallNBExtensionApp(BaseExtensionApp): - """Entry point for uninstalling notebook extensions""" - version = __version__ - description = """Uninstall Jupyter notebook extensions - - Usage - - jupyter nbextension uninstall path/url path/url/entrypoint - jupyter nbextension uninstall --py pythonPackageName - - This uninstalls an nbextension. By default, it uninstalls from the - first directory on the search path where it finds the extension, but you can - uninstall from a specific location using the --user, --sys-prefix or - --system flags, or the --prefix option. - - If you specify the --require option, the named extension will be disabled, - e.g.:: - - jupyter nbextension uninstall myext --require myext/main - - If you use the --py or --python flag, the name should be a Python module. - It will uninstall nbextensions listed in that module, but not the module - itself (which you should uninstall using a package manager such as pip). - """ - - examples = """ - jupyter nbextension uninstall dest/dir dest/dir/extensionjs - jupyter nbextension uninstall --py extensionPyPackage - """ - - aliases = { - "prefix" : "UninstallNBExtensionApp.prefix", - "nbextensions" : "UninstallNBExtensionApp.nbextensions_dir", - "require": "UninstallNBExtensionApp.require", - } - flags = BaseExtensionApp.flags.copy() - flags['system'] = ({'UninstallNBExtensionApp': {'system': True}}, - "Uninstall specifically from systemwide installation directory") - - prefix = Unicode('', config=True, - help="Installation prefix. Overrides --user, --sys-prefix and --system" - ) - nbextensions_dir = Unicode('', config=True, - help="Full path to nbextensions dir (probably use prefix or user)" - ) - require = Unicode('', config=True, help="require.js module to disable loading") - system = Bool(False, config=True, - help="Uninstall specifically from systemwide installation directory" - ) - - def _config_file_name_default(self): - """The default config file name.""" - return 'jupyter_notebook_config' - - def uninstall_extension(self): - """Uninstall an nbextension from a specific location""" - kwargs = { - 'user': self.user, - 'sys_prefix': self.sys_prefix, - 'prefix': self.prefix, - 'nbextensions_dir': self.nbextensions_dir, - 'logger': self.log - } - - if self.python: - uninstall_nbextension_python(self.extra_args[0], **kwargs) - else: - if self.require: - kwargs['require'] = self.require - uninstall_nbextension(self.extra_args[0], **kwargs) - - def find_uninstall_extension(self): - """Uninstall an nbextension from an unspecified location""" - name = self.extra_args[0] - if self.python: - _, nbexts = _get_nbextension_metadata(name) - changed = False - for nbext in nbexts: - if _find_uninstall_nbextension(nbext['dest'], logger=self.log): - changed = True - - # Also disable it in config. - for section in NBCONFIG_SECTIONS: - _find_disable_nbextension(section, nbext['require'], - logger=self.log) - - else: - changed = _find_uninstall_nbextension(name, logger=self.log) - - if not changed: - print("No installed extension %r found." % name) - - if self.require: - for section in NBCONFIG_SECTIONS: - _find_disable_nbextension(section, self.require, - logger=self.log) - - def start(self): - if not self.extra_args: - sys.exit('Please specify an nbextension to uninstall') - elif len(self.extra_args) > 1: - sys.exit("Only one nbextension allowed at a time. " - "Call multiple times to uninstall multiple extensions.") - elif (self.user or self.sys_prefix or self.system or self.prefix - or self.nbextensions_dir): - # The user has specified a location from which to uninstall. - try: - self.uninstall_extension() - except ArgumentConflict as e: - sys.exit(str(e)) - else: - # Uninstall wherever it is. - self.find_uninstall_extension() - - -class ToggleNBExtensionApp(BaseExtensionApp): - """A base class for apps that enable/disable extensions""" - name = "jupyter nbextension enable/disable" - version = __version__ - description = "Enable/disable an nbextension in configuration." - - section = Unicode('notebook', config=True, - help="""Which config section to add the extension to, 'common' will affect all pages.""" - ) - user = Bool(True, config=True, help="Apply the configuration only for the current user (default)") - - aliases = {'section': 'ToggleNBExtensionApp.section'} - - _toggle_value = None - - def _config_file_name_default(self): - """The default config file name.""" - return 'jupyter_notebook_config' - - def toggle_nbextension_python(self, module): - """Toggle some extensions in an importable Python module. - - Returns a list of booleans indicating whether the state was changed as - requested. - - Parameters - ---------- - module : str - Importable Python module exposing the - magic-named `_jupyter_nbextension_paths` function - """ - toggle = (enable_nbextension_python if self._toggle_value - else disable_nbextension_python) - return toggle(module, - user=self.user, - sys_prefix=self.sys_prefix, - logger=self.log) - - def toggle_nbextension(self, require): - """Toggle some a named nbextension by require-able AMD module. - - Returns whether the state was changed as requested. - - Parameters - ---------- - require : str - require.js path used to load the nbextension - """ - toggle = (enable_nbextension if self._toggle_value - else disable_nbextension) - return toggle(self.section, require, - user=self.user, sys_prefix=self.sys_prefix, - logger=self.log) - - def start(self): - if not self.extra_args: - sys.exit('Please specify an nbextension/package to enable or disable') - elif len(self.extra_args) > 1: - sys.exit('Please specify one nbextension/package at a time') - if self.python: - self.toggle_nbextension_python(self.extra_args[0]) - else: - self.toggle_nbextension(self.extra_args[0]) - - -class EnableNBExtensionApp(ToggleNBExtensionApp): - """An App that enables nbextensions""" - name = "jupyter nbextension enable" - description = """ - Enable an nbextension in frontend configuration. - - Usage - jupyter nbextension enable [--system|--sys-prefix] - """ - _toggle_value = True - - -class DisableNBExtensionApp(ToggleNBExtensionApp): - """An App that disables nbextensions""" - name = "jupyter nbextension disable" - description = """ - Disable an nbextension in frontend configuration. - - Usage - jupyter nbextension disable [--system|--sys-prefix] - """ - _toggle_value = None - - -class ListNBExtensionsApp(BaseExtensionApp): - """An App that lists and validates nbextensions""" - name = "jupyter nbextension list" - version = __version__ - description = "List all nbextensions known by the configuration system" - - def list_nbextensions(self): - """List all the nbextensions""" - config_dirs = [os.path.join(p, 'nbconfig') for p in jupyter_config_path()] - - print("Known nbextensions:") - - for config_dir in config_dirs: - head = u' config dir: {}'.format(config_dir) - head_shown = False - - cm = BaseJSONConfigManager(parent=self, config_dir=config_dir) - for section in NBCONFIG_SECTIONS: - data = cm.get(section) - if 'load_extensions' in data: - if not head_shown: - # only show heading if there is an nbextension here - print(head) - head_shown = True - print(u' {} section'.format(section)) - - for require, enabled in data['load_extensions'].items(): - print(u' {} {}'.format( - require, - GREEN_ENABLED if enabled else RED_DISABLED)) - if enabled: - validate_nbextension(require, logger=self.log) - - def start(self): - """Perform the App's functions as configured""" - self.list_nbextensions() - - -_examples = """ -jupyter nbextension list # list all configured nbextensions -jupyter nbextension install --py # install an nbextension from a Python package -jupyter nbextension enable --py # enable all nbextensions in a Python package -jupyter nbextension disable --py # disable all nbextensions in a Python package -jupyter nbextension uninstall --py # uninstall an nbextension in a Python package -""" - -class NBExtensionApp(BaseExtensionApp): - """Base jupyter nbextension command entry point""" - name = "jupyter nbextension" - version = __version__ - description = "Work with Jupyter notebook extensions" - examples = _examples - - subcommands = dict( - install=(InstallNBExtensionApp,"Install an nbextension"), - enable=(EnableNBExtensionApp, "Enable an nbextension"), - disable=(DisableNBExtensionApp, "Disable an nbextension"), - uninstall=(UninstallNBExtensionApp, "Uninstall an nbextension"), - list=(ListNBExtensionsApp, "List nbextensions") - ) - - def start(self): - """Perform the App's functions as configured""" - super().start() - - # The above should have called a subcommand and raised NoStart; if we - # get here, it didn't, so we should self.log.info a message. - subcmds = ", ".join(sorted(self.subcommands)) - sys.exit("Please supply at least one subcommand: %s" % subcmds) - -main = NBExtensionApp.launch_instance - -#------------------------------------------------------------------------------ -# Private API -#------------------------------------------------------------------------------ - - -def _should_copy(src, dest, logger=None): - """Should a file be copied, if it doesn't exist, or is newer? - - Returns whether the file needs to be updated. - - Parameters - ---------- - - src : string - A path that should exist from which to copy a file - src : string - A path that might exist to which to copy a file - logger : Jupyter logger [optional] - Logger instance to use - """ - if not os.path.exists(dest): - return True - if os.stat(src).st_mtime - os.stat(dest).st_mtime > 1e-6: - # we add a fudge factor to work around a bug in python 2.x - # that was fixed in python 3.x: https://bugs.python.org/issue12904 - if logger: - logger.warn("Out of date: %s" % dest) - return True - if logger: - logger.info("Up to date: %s" % dest) - return False - - -def _maybe_copy(src, dest, logger=None): - """Copy a file if it needs updating. - - Parameters - ---------- - - src : string - A path that should exist from which to copy a file - src : string - A path that might exist to which to copy a file - logger : Jupyter logger [optional] - Logger instance to use - """ - if _should_copy(src, dest, logger=logger): - if logger: - logger.info("Copying: %s -> %s" % (src, dest)) - shutil.copy2(src, dest) - - -def _safe_is_tarfile(path): - """Safe version of is_tarfile, return False on IOError. - - Returns whether the file exists and is a tarfile. - - Parameters - ---------- - - path : string - A path that might not exist and or be a tarfile - """ - try: - return tarfile.is_tarfile(path) - except IOError: - return False - - -def _get_nbextension_dir(user=False, sys_prefix=False, prefix=None, nbextensions_dir=None): - """Return the nbextension directory specified - - Parameters - ---------- - - user : bool [default: False] - Get the user's .jupyter/nbextensions directory - sys_prefix : bool [default: False] - Get sys.prefix, i.e. ~/.envs/my-env/share/jupyter/nbextensions - prefix : str [optional] - Get custom prefix - nbextensions_dir : str [optional] - Get what you put in - """ - conflicting = [ - ('user', user), - ('prefix', prefix), - ('nbextensions_dir', nbextensions_dir), - ('sys_prefix', sys_prefix), - ] - conflicting_set = ['{}={!r}'.format(n, v) for n, v in conflicting if v] - if len(conflicting_set) > 1: - raise ArgumentConflict( - "cannot specify more than one of user, sys_prefix, prefix, or nbextensions_dir, but got: {}" - .format(', '.join(conflicting_set))) - if user: - nbext = pjoin(jupyter_data_dir(), u'nbextensions') - elif sys_prefix: - nbext = pjoin(ENV_JUPYTER_PATH[0], u'nbextensions') - elif prefix: - nbext = pjoin(prefix, 'share', 'jupyter', 'nbextensions') - elif nbextensions_dir: - nbext = nbextensions_dir - else: - nbext = pjoin(SYSTEM_JUPYTER_PATH[0], 'nbextensions') - return nbext - - -def _get_nbextension_metadata(module): - """Get the list of nbextension paths associated with a Python module. - - Returns a tuple of (the module, [{ - 'section': 'notebook', - 'src': 'mockextension', - 'dest': '_mockdestination', - 'require': '_mockdestination/index' - }]) - - Parameters - ---------- - - module : str - Importable Python module exposing the - magic-named `_jupyter_nbextension_paths` function - """ - m = import_item(module) - if not hasattr(m, '_jupyter_nbextension_paths'): - raise KeyError('The Python module {} is not a valid nbextension, ' - 'it is missing the `_jupyter_nbextension_paths()` method.'.format(module)) - nbexts = m._jupyter_nbextension_paths() - return m, nbexts - - - -if __name__ == '__main__': - main() diff --git a/notebook/notebook/__init__.py b/notebook/notebook/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/notebook/handlers.py b/notebook/notebook/handlers.py deleted file mode 100644 index 638931d6b..000000000 --- a/notebook/notebook/handlers.py +++ /dev/null @@ -1,114 +0,0 @@ -"""Tornado handlers for the live notebook view.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from collections import namedtuple -import os -from tornado import ( - gen, web, -) -HTTPError = web.HTTPError - -from ..base.handlers import ( - IPythonHandler, FilesRedirectHandler, path_regex, -) -from ..utils import ( - maybe_future, url_escape, -) -from ..transutils import _ - - -def get_frontend_exporters(): - from nbconvert.exporters.base import get_export_names, get_exporter - - # name=exporter_name, display=export_from_notebook+extension - ExporterInfo = namedtuple('ExporterInfo', ['name', 'display']) - - default_exporters = [ - ExporterInfo(name='html', display='HTML (.html)'), - ExporterInfo(name='latex', display='LaTeX (.tex)'), - ExporterInfo(name='markdown', display='Markdown (.md)'), - ExporterInfo(name='notebook', display='Notebook (.ipynb)'), - ExporterInfo(name='pdf', display='PDF via LaTeX (.pdf)'), - ExporterInfo(name='rst', display='reST (.rst)'), - ExporterInfo(name='script', display='Script (.txt)'), - ExporterInfo(name='slides', display='Reveal.js slides (.slides.html)') - ] - - frontend_exporters = [] - for name in get_export_names(): - exporter_class = get_exporter(name) - exporter_instance = exporter_class() - ux_name = getattr(exporter_instance, 'export_from_notebook', None) - super_uxname = getattr(super(exporter_class, exporter_instance), - 'export_from_notebook', None) - - # Ensure export_from_notebook is explicitly defined & not inherited - if ux_name is not None and ux_name != super_uxname: - display = _('{} ({})'.format(ux_name, - exporter_instance.file_extension)) - frontend_exporters.append(ExporterInfo(name, display)) - - # Ensure default_exporters are in frontend_exporters if not already - # This protects against nbconvert versions lower than 5.5 - names = set(exporter.name.lower() for exporter in frontend_exporters) - for exporter in default_exporters: - if exporter.name not in names: - frontend_exporters.append(exporter) - - # Protect against nbconvert 5.5.0 - python_exporter = ExporterInfo(name='python', display='python (.py)') - if python_exporter in frontend_exporters: - frontend_exporters.remove(python_exporter) - - # Protect against nbconvert 5.4.x - template_exporter = ExporterInfo(name='custom', display='custom (.txt)') - if template_exporter in frontend_exporters: - frontend_exporters.remove(template_exporter) - return sorted(frontend_exporters) - - -class NotebookHandler(IPythonHandler): - - @web.authenticated - @gen.coroutine - def get(self, path): - """get renders the notebook template if a name is given, or - redirects to the '/files/' handler if the name is not given.""" - path = path.strip('/') - cm = self.contents_manager - - # will raise 404 on not found - try: - model = yield maybe_future(cm.get(path, content=False)) - except web.HTTPError as e: - if e.status_code == 404 and 'files' in path.split('/'): - # 404, but '/files/' in URL, let FilesRedirect take care of it - return FilesRedirectHandler.redirect_to_files(self, path) - else: - raise - if model['type'] != 'notebook': - # not a notebook, redirect to files - return FilesRedirectHandler.redirect_to_files(self, path) - name = path.rsplit('/', 1)[-1] - self.write(self.render_template('notebook.html', - notebook_path=path, - notebook_name=name, - kill_kernel=False, - mathjax_url=self.mathjax_url, - mathjax_config=self.mathjax_config, - get_frontend_exporters=get_frontend_exporters - ) - ) - - -#----------------------------------------------------------------------------- -# URL to handler mappings -#----------------------------------------------------------------------------- - - -default_handlers = [ - (r"/notebooks%s" % path_regex, NotebookHandler), -] - diff --git a/notebook/notebookapp.py b/notebook/notebookapp.py deleted file mode 100755 index e07bfcf50..000000000 --- a/notebook/notebookapp.py +++ /dev/null @@ -1,2431 +0,0 @@ -"""A tornado based Jupyter notebook server.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import notebook -import asyncio -import binascii -import datetime -import errno -import functools -import gettext -import hashlib -import hmac -import importlib -import inspect -import io -import ipaddress -import json -import logging -import mimetypes -import os -import random -import re -import select -import signal -import socket -import stat -import sys -import tempfile -import threading -import time -import warnings -import webbrowser - -try: - import resource -except ImportError: - # Windows - resource = None - -from base64 import encodebytes - -from jinja2 import Environment, FileSystemLoader - -from notebook.transutils import trans, _ - -# check for tornado 3.1.0 -try: - import tornado -except ImportError as e: - raise ImportError(_("The Jupyter Notebook requires tornado >= 5.0")) from e -try: - version_info = tornado.version_info -except AttributeError as e: - raise ImportError(_("The Jupyter Notebook requires tornado >= 5.0, but you have < 1.1.0")) from e -if version_info < (5,0): - raise ImportError(_("The Jupyter Notebook requires tornado >= 5.0, but you have %s") % tornado.version) - -from tornado import httpserver -from tornado import ioloop -from tornado import web -from tornado.httputil import url_concat -from tornado.log import LogFormatter, app_log, access_log, gen_log -if not sys.platform.startswith('win'): - from tornado.netutil import bind_unix_socket - -from notebook import ( - DEFAULT_NOTEBOOK_PORT, - DEFAULT_STATIC_FILES_PATH, - DEFAULT_TEMPLATE_PATH_LIST, - __version__, -) - - -from .base.handlers import Template404, RedirectWithParams -from .log import log_request -from .services.kernels.kernelmanager import MappingKernelManager, AsyncMappingKernelManager -from .services.config import ConfigManager -from .services.contents.manager import ContentsManager -from .services.contents.filemanager import FileContentsManager -from .services.contents.largefilemanager import LargeFileManager -from .services.sessions.sessionmanager import SessionManager -from .gateway.managers import GatewayKernelManager, GatewayKernelSpecManager, GatewaySessionManager, GatewayClient - -from .auth.login import LoginHandler -from .auth.logout import LogoutHandler -from .base.handlers import FileFindHandler - -from traitlets.config import Config -from traitlets.config.application import catch_config_error, boolean_flag -from jupyter_core.application import ( - JupyterApp, base_flags, base_aliases, -) -from jupyter_core.paths import jupyter_config_path -from jupyter_client import KernelManager -from jupyter_client.kernelspec import KernelSpecManager -from jupyter_client.session import Session -from nbformat.sign import NotebookNotary -from traitlets import ( - Any, Dict, Unicode, Integer, List, Bool, Bytes, Instance, - TraitError, Type, Float, observe, default, validate -) -from ipython_genutils import py3compat -from jupyter_core.paths import jupyter_runtime_dir, jupyter_path -from notebook._sysinfo import get_sys_info - -from ._tz import utcnow, utcfromtimestamp -from .utils import ( - check_pid, - pathname2url, - run_sync, - unix_socket_in_use, - url_escape, - url_path_join, - urldecode_unix_socket_path, - urlencode_unix_socket, - urlencode_unix_socket_path, - urljoin, -) -from .traittypes import TypeFromClasses - -# Check if we can use async kernel management -try: - from jupyter_client import AsyncMultiKernelManager - async_kernel_mgmt_available = True -except ImportError: - async_kernel_mgmt_available = False - -# Tolerate missing terminado package. -try: - from .terminal import TerminalManager - terminado_available = True -except ImportError: - terminado_available = False - -#----------------------------------------------------------------------------- -# Module globals -#----------------------------------------------------------------------------- - -_examples = """ -jupyter notebook # start the notebook -jupyter notebook --certfile=mycert.pem # use SSL/TLS certificate -jupyter notebook password # enter a password to protect the server -""" - -#----------------------------------------------------------------------------- -# Helper functions -#----------------------------------------------------------------------------- - -def random_ports(port, n): - """Generate a list of n random ports near the given port. - - The first 5 ports will be sequential, and the remaining n-5 will be - randomly selected in the range [port-2*n, port+2*n]. - """ - for i in range(min(5, n)): - yield port + i - for i in range(n-5): - yield max(1, port + random.randint(-2*n, 2*n)) - -def load_handlers(name): - """Load the (URL pattern, handler) tuples for each component.""" - mod = __import__(name, fromlist=['default_handlers']) - return mod.default_handlers - -#----------------------------------------------------------------------------- -# The Tornado web application -#----------------------------------------------------------------------------- - - -class NotebookWebApplication(web.Application): - - def __init__(self, jupyter_app, kernel_manager, contents_manager, - session_manager, kernel_spec_manager, - config_manager, extra_services, log, - base_url, default_url, settings_overrides, jinja_env_options): - - settings = self.init_settings( - jupyter_app, kernel_manager, contents_manager, - session_manager, kernel_spec_manager, config_manager, - extra_services, log, base_url, - default_url, settings_overrides, jinja_env_options) - handlers = self.init_handlers(settings) - - if settings['autoreload']: - log.info('Autoreload enabled: the webapp will restart when any Python src file changes.') - - super().__init__(handlers, **settings) - - def init_settings(self, jupyter_app, kernel_manager, contents_manager, - session_manager, kernel_spec_manager, - config_manager, extra_services, - log, base_url, default_url, settings_overrides, - jinja_env_options=None): - - _template_path = settings_overrides.get( - "template_path", - jupyter_app.template_file_path, - ) - if isinstance(_template_path, py3compat.string_types): - _template_path = (_template_path,) - template_path = [os.path.expanduser(path) for path in _template_path] - - jenv_opt = {"autoescape": True} - jenv_opt.update(jinja_env_options if jinja_env_options else {}) - - env = Environment(loader=FileSystemLoader(template_path), extensions=['jinja2.ext.i18n'], **jenv_opt) - sys_info = get_sys_info() - - # If the user is running the notebook in a git directory, make the assumption - # that this is a dev install and suggest to the developer `npm run build:watch`. - base_dir = os.path.realpath(os.path.join(__file__, '..', '..')) - dev_mode = os.path.exists(os.path.join(base_dir, '.git')) - - nbui = gettext.translation('nbui', localedir=os.path.join(base_dir, 'notebook/i18n'), fallback=True) - env.install_gettext_translations(nbui, newstyle=False) - - if dev_mode: - DEV_NOTE_NPM = """It looks like you're running the notebook from source. - If you're working on the Javascript of the notebook, try running - - %s - - in another terminal window to have the system incrementally - watch and build the notebook's JavaScript for you, as you make changes.""" % 'npm run build:watch' - log.info(DEV_NOTE_NPM) - - if sys_info['commit_source'] == 'repository': - # don't cache (rely on 304) when working from master - version_hash = '' - else: - # reset the cache on server restart - version_hash = datetime.datetime.now().strftime("%Y%m%d%H%M%S") - - if jupyter_app.ignore_minified_js: - log.warning(_("""The `ignore_minified_js` flag is deprecated and no longer works.""")) - log.warning(_("""Alternatively use `%s` when working on the notebook's Javascript and LESS""") % 'npm run build:watch') - warnings.warn(_("The `ignore_minified_js` flag is deprecated and will be removed in Notebook 6.0"), DeprecationWarning) - - now = utcnow() - - root_dir = contents_manager.root_dir - home = py3compat.str_to_unicode(os.path.expanduser('~'), encoding=sys.getfilesystemencoding()) - if root_dir.startswith(home + os.path.sep): - # collapse $HOME to ~ - root_dir = '~' + root_dir[len(home):] - - # Use the NotebookApp logger and its formatting for tornado request logging. - log_function = functools.partial( - log_request, log=log, log_json=jupyter_app.log_json) - settings = dict( - # basics - log_function=log_function, - base_url=base_url, - default_url=default_url, - template_path=template_path, - static_path=jupyter_app.static_file_path, - static_custom_path=jupyter_app.static_custom_path, - static_handler_class = FileFindHandler, - static_url_prefix = url_path_join(base_url,'/static/'), - static_handler_args = { - # don't cache custom.js - 'no_cache_paths': [url_path_join(base_url, 'static', 'custom')], - }, - version_hash=version_hash, - ignore_minified_js=jupyter_app.ignore_minified_js, - - # rate limits - iopub_msg_rate_limit=jupyter_app.iopub_msg_rate_limit, - iopub_data_rate_limit=jupyter_app.iopub_data_rate_limit, - rate_limit_window=jupyter_app.rate_limit_window, - - # authentication - cookie_secret=jupyter_app.cookie_secret, - login_url=url_path_join(base_url,'/login'), - login_handler_class=jupyter_app.login_handler_class, - logout_handler_class=jupyter_app.logout_handler_class, - password=jupyter_app.password, - xsrf_cookies=True, - disable_check_xsrf=jupyter_app.disable_check_xsrf, - allow_remote_access=jupyter_app.allow_remote_access, - local_hostnames=jupyter_app.local_hostnames, - authenticate_prometheus=jupyter_app.authenticate_prometheus, - - # managers - kernel_manager=kernel_manager, - contents_manager=contents_manager, - session_manager=session_manager, - kernel_spec_manager=kernel_spec_manager, - config_manager=config_manager, - - # handlers - extra_services=extra_services, - - # Jupyter stuff - started=now, - # place for extensions to register activity - # so that they can prevent idle-shutdown - last_activity_times={}, - jinja_template_vars=jupyter_app.jinja_template_vars, - nbextensions_path=jupyter_app.nbextensions_path, - websocket_url=jupyter_app.websocket_url, - mathjax_url=jupyter_app.mathjax_url, - mathjax_config=jupyter_app.mathjax_config, - shutdown_button=jupyter_app.quit_button, - config=jupyter_app.config, - config_dir=jupyter_app.config_dir, - allow_password_change=jupyter_app.allow_password_change, - server_root_dir=root_dir, - jinja2_env=env, - terminals_available=terminado_available and jupyter_app.terminals_enabled, - ) - - # allow custom overrides for the tornado web app. - settings.update(settings_overrides) - return settings - - def init_handlers(self, settings): - """Load the (URL pattern, handler) tuples for each component.""" - - # Order matters. The first handler to match the URL will handle the request. - handlers = [] - # load extra services specified by users before default handlers - for service in settings['extra_services']: - handlers.extend(load_handlers(service)) - handlers.extend(load_handlers('notebook.tree.handlers')) - handlers.extend([(r"/login", settings['login_handler_class'])]) - handlers.extend([(r"/logout", settings['logout_handler_class'])]) - handlers.extend(load_handlers('notebook.files.handlers')) - handlers.extend(load_handlers('notebook.view.handlers')) - handlers.extend(load_handlers('notebook.notebook.handlers')) - handlers.extend(load_handlers('notebook.nbconvert.handlers')) - handlers.extend(load_handlers('notebook.bundler.handlers')) - handlers.extend(load_handlers('notebook.kernelspecs.handlers')) - handlers.extend(load_handlers('notebook.edit.handlers')) - handlers.extend(load_handlers('notebook.services.api.handlers')) - handlers.extend(load_handlers('notebook.services.config.handlers')) - handlers.extend(load_handlers('notebook.services.contents.handlers')) - handlers.extend(load_handlers('notebook.services.sessions.handlers')) - handlers.extend(load_handlers('notebook.services.nbconvert.handlers')) - handlers.extend(load_handlers('notebook.services.security.handlers')) - handlers.extend(load_handlers('notebook.services.shutdown')) - handlers.extend(load_handlers('notebook.services.kernels.handlers')) - handlers.extend(load_handlers('notebook.services.kernelspecs.handlers')) - - handlers.extend(settings['contents_manager'].get_extra_handlers()) - - # If gateway mode is enabled, replace appropriate handlers to perform redirection - if GatewayClient.instance().gateway_enabled: - # for each handler required for gateway, locate its pattern - # in the current list and replace that entry... - gateway_handlers = load_handlers('notebook.gateway.handlers') - for i, gwh in enumerate(gateway_handlers): - for j, h in enumerate(handlers): - if gwh[0] == h[0]: - handlers[j] = (gwh[0], gwh[1]) - break - - handlers.append( - (r"/nbextensions/(.*)", FileFindHandler, { - 'path': settings['nbextensions_path'], - 'no_cache_paths': ['/'], # don't cache anything in nbextensions - }), - ) - handlers.append( - (r"/custom/(.*)", FileFindHandler, { - 'path': settings['static_custom_path'], - 'no_cache_paths': ['/'], # don't cache anything in custom - }) - ) - # register base handlers last - handlers.extend(load_handlers('notebook.base.handlers')) - # set the URL that will be redirected from `/` - handlers.append( - (r'/?', RedirectWithParams, { - 'url' : settings['default_url'], - 'permanent': False, # want 302, not 301 - }) - ) - - # prepend base_url onto the patterns that we match - new_handlers = [] - for handler in handlers: - pattern = url_path_join(settings['base_url'], handler[0]) - new_handler = tuple([pattern] + list(handler[1:])) - new_handlers.append(new_handler) - # add 404 on the end, which will catch everything that falls through - new_handlers.append((r'(.*)', Template404)) - return new_handlers - - def last_activity(self): - """Get a UTC timestamp for when the server last did something. - - Includes: API activity, kernel activity, kernel shutdown, and terminal - activity. - """ - sources = [ - self.settings['started'], - self.settings['kernel_manager'].last_kernel_activity, - ] - try: - sources.append(self.settings['api_last_activity']) - except KeyError: - pass - try: - sources.append(self.settings['terminal_last_activity']) - except KeyError: - pass - sources.extend(self.settings['last_activity_times'].values()) - return max(sources) - - -class NotebookPasswordApp(JupyterApp): - """Set a password for the notebook server. - - Setting a password secures the notebook server - and removes the need for token-based authentication. - """ - - description = __doc__ - - def _config_file_default(self): - return os.path.join(self.config_dir, 'jupyter_notebook_config.json') - - def start(self): - from .auth.security import set_password - set_password(config_file=self.config_file) - self.log.info("Wrote hashed password to %s" % self.config_file) - - -def shutdown_server(server_info, timeout=5, log=None): - """Shutdown a notebook server in a separate process. - - *server_info* should be a dictionary as produced by list_running_servers(). - - Will first try to request shutdown using /api/shutdown . - On Unix, if the server is still running after *timeout* seconds, it will - send SIGTERM. After another timeout, it escalates to SIGKILL. - - Returns True if the server was stopped by any means, False if stopping it - failed (on Windows). - """ - from tornado import gen - from tornado.httpclient import AsyncHTTPClient, HTTPClient, HTTPRequest - from tornado.netutil import Resolver - url = server_info['url'] - pid = server_info['pid'] - resolver = None - - # UNIX Socket handling. - if url.startswith('http+unix://'): - # This library doesn't understand our URI form, but it's just HTTP. - url = url.replace('http+unix://', 'http://') - - class UnixSocketResolver(Resolver): - def initialize(self, resolver): - self.resolver = resolver - - def close(self): - self.resolver.close() - - @gen.coroutine - def resolve(self, host, port, *args, **kwargs): - raise gen.Return([ - (socket.AF_UNIX, urldecode_unix_socket_path(host)) - ]) - - resolver = UnixSocketResolver(resolver=Resolver()) - - req = HTTPRequest(url + 'api/shutdown', method='POST', body=b'', headers={ - 'Authorization': 'token ' + server_info['token'] - }) - if log: log.debug("POST request to %sapi/shutdown", url) - AsyncHTTPClient.configure(None, resolver=resolver) - HTTPClient(AsyncHTTPClient).fetch(req) - - # Poll to see if it shut down. - for _ in range(timeout*10): - if not check_pid(pid): - if log: log.debug("Server PID %s is gone", pid) - return True - time.sleep(0.1) - - if sys.platform.startswith('win'): - return False - - if log: log.debug("SIGTERM to PID %s", pid) - os.kill(pid, signal.SIGTERM) - - # Poll to see if it shut down. - for _ in range(timeout * 10): - if not check_pid(pid): - if log: log.debug("Server PID %s is gone", pid) - return True - time.sleep(0.1) - - if log: log.debug("SIGKILL to PID %s", pid) - os.kill(pid, signal.SIGKILL) - return True # SIGKILL cannot be caught - - -class NbserverStopApp(JupyterApp): - version = __version__ - description="Stop currently running notebook server." - - port = Integer(DEFAULT_NOTEBOOK_PORT, config=True, - help="Port of the server to be killed. Default %s" % DEFAULT_NOTEBOOK_PORT) - - sock = Unicode(u'', config=True, - help="UNIX socket of the server to be killed.") - - def parse_command_line(self, argv=None): - super().parse_command_line(argv) - if self.extra_args: - try: - self.port = int(self.extra_args[0]) - except ValueError: - # self.extra_args[0] was not an int, so it must be a string (unix socket). - self.sock = self.extra_args[0] - - def shutdown_server(self, server): - return shutdown_server(server, log=self.log) - - def _shutdown_or_exit(self, target_endpoint, server): - print("Shutting down server on %s..." % target_endpoint) - server_stopped = self.shutdown_server(server) - if not server_stopped and sys.platform.startswith('win'): - # the pid check on Windows appears to be unreliable, so fetch another - # list of servers and ensure our server is not in the list before - # sending the wrong impression. - servers = list(list_running_servers(self.runtime_dir)) - if server not in servers: - server_stopped = True - if not server_stopped: - sys.exit("Could not stop server on %s" % target_endpoint) - - @staticmethod - def _maybe_remove_unix_socket(socket_path): - try: - os.unlink(socket_path) - except (OSError, IOError): - pass - - def start(self): - servers = list(list_running_servers(self.runtime_dir)) - if not servers: - self.exit("There are no running servers (per %s)" % self.runtime_dir) - - for server in servers: - if self.sock: - sock = server.get('sock', None) - if sock and sock == self.sock: - self._shutdown_or_exit(sock, server) - # Attempt to remove the UNIX socket after stopping. - self._maybe_remove_unix_socket(sock) - return - elif self.port: - port = server.get('port', None) - if port == self.port: - self._shutdown_or_exit(port, server) - return - else: - current_endpoint = self.sock or self.port - print( - "There is currently no server running on {}".format(current_endpoint), - file=sys.stderr - ) - print("Ports/sockets currently in use:", file=sys.stderr) - for server in servers: - print(" - {}".format(server.get('sock') or server['port']), file=sys.stderr) - self.exit(1) - - -class NbserverListApp(JupyterApp): - version = __version__ - description=_("List currently running notebook servers.") - - flags = dict( - jsonlist=({'NbserverListApp': {'jsonlist': True}}, - _("Produce machine-readable JSON list output.")), - json=({'NbserverListApp': {'json': True}}, - _("Produce machine-readable JSON object on each line of output.")), - ) - - jsonlist = Bool(False, config=True, - help=_("If True, the output will be a JSON list of objects, one per " - "active notebook server, each with the details from the " - "relevant server info file.")) - json = Bool(False, config=True, - help=_("If True, each line of output will be a JSON object with the " - "details from the server info file. For a JSON list output, " - "see the NbserverListApp.jsonlist configuration value")) - - def start(self): - serverinfo_list = list(list_running_servers(self.runtime_dir)) - if self.jsonlist: - print(json.dumps(serverinfo_list, indent=2)) - elif self.json: - for serverinfo in serverinfo_list: - print(json.dumps(serverinfo)) - else: - print("Currently running servers:") - for serverinfo in serverinfo_list: - url = serverinfo['url'] - if serverinfo.get('token'): - url = url + '?token=%s' % serverinfo['token'] - print(url, "::", serverinfo['notebook_dir']) - -#----------------------------------------------------------------------------- -# Aliases and Flags -#----------------------------------------------------------------------------- - -flags = dict(base_flags) -flags['no-browser']=( - {'NotebookApp' : {'open_browser' : False}}, - _("Don't open the notebook in a browser after startup.") -) -flags['pylab']=( - {'NotebookApp' : {'pylab' : 'warn'}}, - _("DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib.") -) -flags['no-mathjax']=( - {'NotebookApp' : {'enable_mathjax' : False}}, - """Disable MathJax - - MathJax is the javascript library Jupyter uses to render math/LaTeX. It is - very large, so you may want to disable it if you have a slow internet - connection, or for offline use of the notebook. - - When disabled, equations etc. will appear as their untransformed TeX source. - """ -) - -flags['allow-root']=( - {'NotebookApp' : {'allow_root' : True}}, - _("Allow the notebook to be run from root user.") -) - -flags['autoreload'] = ( - {'NotebookApp': {'autoreload': True}}, - """Autoreload the webapp - - Enable reloading of the tornado webapp and all imported Python packages - when any changes are made to any Python src files in Notebook or - extensions. - """ -) - -# Add notebook manager flags -flags.update(boolean_flag('script', 'FileContentsManager.save_script', - 'DEPRECATED, IGNORED', - 'DEPRECATED, IGNORED')) - -aliases = dict(base_aliases) - -aliases.update({ - 'ip': 'NotebookApp.ip', - 'port': 'NotebookApp.port', - 'port-retries': 'NotebookApp.port_retries', - 'sock': 'NotebookApp.sock', - 'sock-mode': 'NotebookApp.sock_mode', - 'transport': 'KernelManager.transport', - 'keyfile': 'NotebookApp.keyfile', - 'certfile': 'NotebookApp.certfile', - 'client-ca': 'NotebookApp.client_ca', - 'notebook-dir': 'NotebookApp.notebook_dir', - 'browser': 'NotebookApp.browser', - 'pylab': 'NotebookApp.pylab', - 'gateway-url': 'GatewayClient.url', -}) - -#----------------------------------------------------------------------------- -# NotebookApp -#----------------------------------------------------------------------------- - -class NotebookApp(JupyterApp): - - name = 'jupyter-notebook' - version = __version__ - description = _("""The Jupyter HTML Notebook. - - This launches a Tornado based HTML Notebook Server that serves up an HTML5/Javascript Notebook client.""") - examples = _examples - aliases = aliases - flags = flags - - classes = [ - KernelManager, Session, MappingKernelManager, KernelSpecManager, - ContentsManager, FileContentsManager, NotebookNotary, - GatewayKernelManager, GatewayKernelSpecManager, GatewaySessionManager, GatewayClient, - ] - if terminado_available: # Only necessary when terminado is available - classes.append(TerminalManager) - - flags = Dict(flags) - aliases = Dict(aliases) - - subcommands = dict( - list=(NbserverListApp, NbserverListApp.description.splitlines()[0]), - stop=(NbserverStopApp, NbserverStopApp.description.splitlines()[0]), - password=(NotebookPasswordApp, NotebookPasswordApp.description.splitlines()[0]), - ) - - _log_formatter_cls = LogFormatter - - _json_logging_import_error_logged = False - - log_json = Bool(False, config=True, - help=_('Set to True to enable JSON formatted logs. ' - 'Run "pip install notebook[json-logging]" to install the ' - 'required dependent packages. Can also be set using the ' - 'environment variable JUPYTER_ENABLE_JSON_LOGGING=true.') - ) - - @default('log_json') - def _default_log_json(self): - """Get the log_json value from the environment.""" - return os.getenv('JUPYTER_ENABLE_JSON_LOGGING', 'false').lower() == 'true' - - @validate('log_json') - def _validate_log_json(self, proposal): - # If log_json=True, see if the json_logging package can be imported and - # override _log_formatter_cls if so. - value = proposal['value'] - if value: - try: - import json_logging - self.log.debug('initializing json logging') - json_logging.init_non_web(enable_json=True) - self._log_formatter_cls = json_logging.JSONLogFormatter - except ImportError: - # If configured for json logs and we can't do it, log a hint. - # Only log the error once though. - if not self._json_logging_import_error_logged: - self.log.warning( - 'Unable to use json logging due to missing packages. ' - 'Run "pip install notebook[json-logging]" to fix.' - ) - self._json_logging_import_error_logged = True - value = False - return value - - @default('log_level') - def _default_log_level(self): - return logging.INFO - - @default('log_datefmt') - def _default_log_datefmt(self): - """Exclude date from default date format""" - return "%H:%M:%S" - - @default('log_format') - def _default_log_format(self): - """override default log format to include time""" - return u"%(color)s[%(levelname)1.1s %(asctime)s.%(msecs).03d %(name)s]%(end_color)s %(message)s" - - ignore_minified_js = Bool(False, - config=True, - help=_('Deprecated: Use minified JS file or not, mainly use during dev to avoid JS recompilation'), - ) - - # file to be opened in the notebook server - file_to_run = Unicode('', config=True) - - # Network related information - - allow_origin = Unicode('', config=True, - help="""Set the Access-Control-Allow-Origin header - - Use '*' to allow any origin to access your server. - - Takes precedence over allow_origin_pat. - """ - ) - - allow_origin_pat = Unicode('', config=True, - help="""Use a regular expression for the Access-Control-Allow-Origin header - - Requests from an origin matching the expression will get replies with: - - Access-Control-Allow-Origin: origin - - where `origin` is the origin of the request. - - Ignored if allow_origin is set. - """ - ) - - allow_credentials = Bool(False, config=True, - help=_("Set the Access-Control-Allow-Credentials: true header") - ) - - allow_root = Bool(False, config=True, - help=_("Whether to allow the user to run the notebook as root.") - ) - - use_redirect_file = Bool(True, config=True, - help="""Disable launching browser by redirect file - - For versions of notebook > 5.7.2, a security feature measure was added that - prevented the authentication token used to launch the browser from being visible. - This feature makes it difficult for other users on a multi-user system from - running code in your Jupyter session as you. - - However, some environments (like Windows Subsystem for Linux (WSL) and Chromebooks), - launching a browser using a redirect file can lead the browser failing to load. - This is because of the difference in file structures/paths between the runtime and - the browser. - - Disabling this setting to False will disable this behavior, allowing the browser - to launch by using a URL and visible token (as before). - """ - ) - - autoreload = Bool(False, config=True, - help= ("Reload the webapp when changes are made to any Python src files.") - ) - - default_url = Unicode('/tree', config=True, - help=_("The default URL to redirect to from `/`") - ) - - ip = Unicode('localhost', config=True, - help=_("The IP address the notebook server will listen on.") - ) - - @default('ip') - def _default_ip(self): - """Return localhost if available, 127.0.0.1 otherwise. - - On some (horribly broken) systems, localhost cannot be bound. - """ - s = socket.socket() - try: - s.bind(('localhost', 0)) - except socket.error as e: - self.log.warning(_("Cannot bind to localhost, using 127.0.0.1 as default ip\n%s"), e) - return '127.0.0.1' - else: - s.close() - return 'localhost' - - @validate('ip') - def _validate_ip(self, proposal): - value = proposal['value'] - if value == u'*': - value = u'' - return value - - custom_display_url = Unicode(u'', config=True, - help=_("""Override URL shown to users. - - Replace actual URL, including protocol, address, port and base URL, - with the given value when displaying URL to the users. Do not change - the actual connection URL. If authentication token is enabled, the - token is added to the custom URL automatically. - - This option is intended to be used when the URL to display to the user - cannot be determined reliably by the Jupyter notebook server (proxified - or containerized setups for example).""") - ) - - port_env = 'JUPYTER_PORT' - port_default_value = DEFAULT_NOTEBOOK_PORT - port = Integer(port_default_value, config=True, - help=_("The port the notebook server will listen on (env: JUPYTER_PORT).") - ) - - @default('port') - def port_default(self): - return int(os.getenv(self.port_env, self.port_default_value)) - - port_retries_env = 'JUPYTER_PORT_RETRIES' - port_retries_default_value = 50 - port_retries = Integer(port_retries_default_value, config=True, - help=_("The number of additional ports to try if the specified port is not " - "available (env: JUPYTER_PORT_RETRIES).") - ) - - @default('port_retries') - def port_retries_default(self): - return int(os.getenv(self.port_retries_env, self.port_retries_default_value)) - - - sock = Unicode(u'', config=True, - help=_("The UNIX socket the notebook server will listen on.") - ) - - sock_mode = Unicode('0600', config=True, - help=_("The permissions mode for UNIX socket creation (default: 0600).") - ) - - @validate('sock_mode') - def _validate_sock_mode(self, proposal): - value = proposal['value'] - try: - converted_value = int(value.encode(), 8) - assert all(( - # Ensure the mode is at least user readable/writable. - bool(converted_value & stat.S_IRUSR), - bool(converted_value & stat.S_IWUSR), - # And isn't out of bounds. - converted_value <= 2 ** 12 - )) - except ValueError as e: - raise TraitError( - 'invalid --sock-mode value: %s, please specify as e.g. "0600"' % value - ) from e - except AssertionError as e: - raise TraitError( - 'invalid --sock-mode value: %s, must have u+rw (0600) at a minimum' % value - ) from e - return value - - - certfile = Unicode(u'', config=True, - help=_("""The full path to an SSL/TLS certificate file.""") - ) - - keyfile = Unicode(u'', config=True, - help=_("""The full path to a private key file for usage with SSL/TLS.""") - ) - - client_ca = Unicode(u'', config=True, - help=_("""The full path to a certificate authority certificate for SSL/TLS client authentication.""") - ) - - cookie_secret_file = Unicode(config=True, - help=_("""The file where the cookie secret is stored.""") - ) - - @default('cookie_secret_file') - def _default_cookie_secret_file(self): - return os.path.join(self.runtime_dir, 'notebook_cookie_secret') - - cookie_secret = Bytes(b'', config=True, - help="""The random bytes used to secure cookies. - By default this is a new random number every time you start the Notebook. - Set it to a value in a config file to enable logins to persist across server sessions. - - Note: Cookie secrets should be kept private, do not share config files with - cookie_secret stored in plaintext (you can read the value from a file). - """ - ) - - @default('cookie_secret') - def _default_cookie_secret(self): - if os.path.exists(self.cookie_secret_file): - with io.open(self.cookie_secret_file, 'rb') as f: - key = f.read() - else: - key = encodebytes(os.urandom(32)) - self._write_cookie_secret_file(key) - h = hmac.new(key, digestmod=hashlib.sha256) - h.update(self.password.encode()) - return h.digest() - - def _write_cookie_secret_file(self, secret): - """write my secret to my secret_file""" - self.log.info(_("Writing notebook server cookie secret to %s"), self.cookie_secret_file) - try: - with io.open(self.cookie_secret_file, 'wb') as f: - f.write(secret) - except OSError as e: - self.log.error(_("Failed to write cookie secret to %s: %s"), - self.cookie_secret_file, e) - try: - os.chmod(self.cookie_secret_file, 0o600) - except OSError: - self.log.warning( - _("Could not set permissions on %s"), - self.cookie_secret_file - ) - - token = Unicode('', - help=_("""Token used for authenticating first-time connections to the server. - - The token can be read from the file referenced by JUPYTER_TOKEN_FILE or set directly - with the JUPYTER_TOKEN environment variable. - - When no password is enabled, - the default is to generate a new, random token. - - Setting to an empty string disables authentication altogether, which is NOT RECOMMENDED. - """) - ).tag(config=True) - - _token_generated = True - - @default('token') - def _token_default(self): - if os.getenv('JUPYTER_TOKEN'): - self._token_generated = False - return os.getenv('JUPYTER_TOKEN') - if os.getenv('JUPYTER_TOKEN_FILE'): - self._token_generated = False - with io.open(os.getenv('JUPYTER_TOKEN_FILE'), "r") as token_file: - return token_file.read() - if self.password: - # no token if password is enabled - self._token_generated = False - return u'' - else: - self._token_generated = True - return binascii.hexlify(os.urandom(24)).decode('ascii') - - max_body_size = Integer(512 * 1024 * 1024, config=True, - help=""" - Sets the maximum allowed size of the client request body, specified in - the Content-Length request header field. If the size in a request - exceeds the configured value, a malformed HTTP message is returned to - the client. - - Note: max_body_size is applied even in streaming mode. - """ - ) - - max_buffer_size = Integer(512 * 1024 * 1024, config=True, - help=""" - Gets or sets the maximum amount of memory, in bytes, that is allocated - for use by the buffer manager. - """ - ) - - min_open_files_limit = Integer(config=True, - help=""" - Gets or sets a lower bound on the open file handles process resource - limit. This may need to be increased if you run into an - OSError: [Errno 24] Too many open files. - This is not applicable when running on Windows. - """) - - @default('min_open_files_limit') - def _default_min_open_files_limit(self): - if resource is None: - # Ignoring min_open_files_limit because the limit cannot be adjusted (for example, on Windows) - return None - - soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) - - DEFAULT_SOFT = 4096 - if hard >= DEFAULT_SOFT: - return DEFAULT_SOFT - - self.log.debug("Default value for min_open_files_limit is ignored (hard=%r, soft=%r)", hard, soft) - - return soft - - @observe('token') - def _token_changed(self, change): - self._token_generated = False - - password = Unicode(u'', config=True, - help="""Hashed password to use for web authentication. - - To generate, type in a python/IPython shell: - - from notebook.auth import passwd; passwd() - - The string should be of the form type:salt:hashed-password. - """ - ) - - password_required = Bool(False, config=True, - help="""Forces users to use a password for the Notebook server. - This is useful in a multi user environment, for instance when - everybody in the LAN can access each other's machine through ssh. - - In such a case, serving the notebook server on localhost is not secure - since any user can connect to the notebook server via ssh. - - """ - ) - - allow_password_change = Bool(True, config=True, - help="""Allow password to be changed at login for the notebook server. - - While logging in with a token, the notebook server UI will give the opportunity to - the user to enter a new password at the same time that will replace - the token login mechanism. - - This can be set to false to prevent changing password from the UI/API. - """ - ) - - - disable_check_xsrf = Bool(False, config=True, - help="""Disable cross-site-request-forgery protection - - Jupyter notebook 4.3.1 introduces protection from cross-site request forgeries, - requiring API requests to either: - - - originate from pages served by this server (validated with XSRF cookie and token), or - - authenticate with a token - - Some anonymous compute resources still desire the ability to run code, - completely without authentication. - These services can disable all authentication and security checks, - with the full knowledge of what that implies. - """ - ) - - allow_remote_access = Bool(config=True, - help="""Allow requests where the Host header doesn't point to a local server - - By default, requests get a 403 forbidden response if the 'Host' header - shows that the browser thinks it's on a non-local domain. - Setting this option to True disables this check. - - This protects against 'DNS rebinding' attacks, where a remote web server - serves you a page and then changes its DNS to send later requests to a - local IP, bypassing same-origin checks. - - Local IP addresses (such as 127.0.0.1 and ::1) are allowed as local, - along with hostnames configured in local_hostnames. - """) - - @default('allow_remote_access') - def _default_allow_remote(self): - """Disallow remote access if we're listening only on loopback addresses""" - - # if blank, self.ip was configured to "*" meaning bind to all interfaces, - # see _valdate_ip - if self.ip == "": - return True - - try: - addr = ipaddress.ip_address(self.ip) - except ValueError: - # Address is a hostname - for info in socket.getaddrinfo(self.ip, self.port, 0, socket.SOCK_STREAM): - addr = info[4][0] - if not py3compat.PY3: - addr = addr.decode('ascii') - - try: - parsed = ipaddress.ip_address(addr.split('%')[0]) - except ValueError: - self.log.warning("Unrecognised IP address: %r", addr) - continue - - # Macs map localhost to 'fe80::1%lo0', a link local address - # scoped to the loopback interface. For now, we'll assume that - # any scoped link-local address is effectively local. - if not (parsed.is_loopback - or (('%' in addr) and parsed.is_link_local)): - return True - return False - else: - return not addr.is_loopback - - local_hostnames = List(Unicode(), ['localhost'], config=True, - help="""Hostnames to allow as local when allow_remote_access is False. - - Local IP addresses (such as 127.0.0.1 and ::1) are automatically accepted - as local as well. - """ - ) - - open_browser = Bool(True, config=True, - help="""Whether to open in a browser after starting. - The specific browser used is platform dependent and - determined by the python standard library `webbrowser` - module, unless it is overridden using the --browser - (NotebookApp.browser) configuration option. - """) - - browser = Unicode(u'', config=True, - help="""Specify what command to use to invoke a web - browser when opening the notebook. If not specified, the - default browser will be determined by the `webbrowser` - standard library module, which allows setting of the - BROWSER environment variable to override it. - """) - - webbrowser_open_new = Integer(2, config=True, - help=_("""Specify Where to open the notebook on startup. This is the - `new` argument passed to the standard library method `webbrowser.open`. - The behaviour is not guaranteed, but depends on browser support. Valid - values are: - - - 2 opens a new tab, - - 1 opens a new window, - - 0 opens in an existing window. - - See the `webbrowser.open` documentation for details. - """)) - - webapp_settings = Dict(config=True, - help=_("DEPRECATED, use tornado_settings") - ) - - @observe('webapp_settings') - def _update_webapp_settings(self, change): - self.log.warning(_("\n webapp_settings is deprecated, use tornado_settings.\n")) - self.tornado_settings = change['new'] - - tornado_settings = Dict(config=True, - help=_("Supply overrides for the tornado.web.Application that the " - "Jupyter notebook uses.")) - - websocket_compression_options = Any(None, config=True, - help=_(""" - Set the tornado compression options for websocket connections. - - This value will be returned from :meth:`WebSocketHandler.get_compression_options`. - None (default) will disable compression. - A dict (even an empty one) will enable compression. - - See the tornado docs for WebSocketHandler.get_compression_options for details. - """) - ) - terminado_settings = Dict(config=True, - help=_('Supply overrides for terminado. Currently only supports "shell_command". ' - 'On Unix, if "shell_command" is not provided, a non-login shell is launched ' - "by default when the notebook server is connected to a terminal, a login " - "shell otherwise.")) - - cookie_options = Dict(config=True, - help=_("Extra keyword arguments to pass to `set_secure_cookie`." - " See tornado's set_secure_cookie docs for details.") - ) - get_secure_cookie_kwargs = Dict(config=True, - help=_("Extra keyword arguments to pass to `get_secure_cookie`." - " See tornado's get_secure_cookie docs for details.") - ) - ssl_options = Dict(config=True, - help=_("""Supply SSL options for the tornado HTTPServer. - See the tornado docs for details.""")) - - jinja_environment_options = Dict(config=True, - help=_("Supply extra arguments that will be passed to Jinja environment.")) - - jinja_template_vars = Dict( - config=True, - help=_("Extra variables to supply to jinja templates when rendering."), - ) - - enable_mathjax = Bool(True, config=True, - help="""Whether to enable MathJax for typesetting math/TeX - - MathJax is the javascript library Jupyter uses to render math/LaTeX. It is - very large, so you may want to disable it if you have a slow internet - connection, or for offline use of the notebook. - - When disabled, equations etc. will appear as their untransformed TeX source. - """ - ) - - @observe('enable_mathjax') - def _update_enable_mathjax(self, change): - """set mathjax url to empty if mathjax is disabled""" - if not change['new']: - self.mathjax_url = u'' - - base_url = Unicode('/', config=True, - help='''The base URL for the notebook server. - - Leading and trailing slashes can be omitted, - and will automatically be added. - ''') - - @validate('base_url') - def _update_base_url(self, proposal): - value = proposal['value'] - if not value.startswith('/'): - value = '/' + value - if not value.endswith('/'): - value = value + '/' - return value - - base_project_url = Unicode('/', config=True, help=_("""DEPRECATED use base_url""")) - - @observe('base_project_url') - def _update_base_project_url(self, change): - self.log.warning(_("base_project_url is deprecated, use base_url")) - self.base_url = change['new'] - - extra_static_paths = List(Unicode(), config=True, - help="""Extra paths to search for serving static files. - - This allows adding javascript/css to be available from the notebook server machine, - or overriding individual files in the IPython""" - ) - - @property - def static_file_path(self): - """return extra paths + the default location""" - return self.extra_static_paths + [DEFAULT_STATIC_FILES_PATH] - - static_custom_path = List(Unicode(), - help=_("""Path to search for custom.js, css""") - ) - - @default('static_custom_path') - def _default_static_custom_path(self): - return [ - os.path.join(d, 'custom') for d in ( - self.config_dir, - DEFAULT_STATIC_FILES_PATH) - ] - - extra_template_paths = List(Unicode(), config=True, - help=_("""Extra paths to search for serving jinja templates. - - Can be used to override templates from notebook.templates.""") - ) - - @property - def template_file_path(self): - """return extra paths + the default locations""" - return self.extra_template_paths + DEFAULT_TEMPLATE_PATH_LIST - - extra_nbextensions_path = List(Unicode(), config=True, - help=_("""extra paths to look for Javascript notebook extensions""") - ) - - extra_services = List(Unicode(), config=True, - help=_("""handlers that should be loaded at higher priority than the default services""") - ) - - @property - def nbextensions_path(self): - """The path to look for Javascript notebook extensions""" - path = self.extra_nbextensions_path + jupyter_path('nbextensions') - # FIXME: remove IPython nbextensions path after a migration period - try: - from IPython.paths import get_ipython_dir - except ImportError: - pass - else: - path.append(os.path.join(get_ipython_dir(), 'nbextensions')) - return path - - websocket_url = Unicode("", config=True, - help="""The base URL for websockets, - if it differs from the HTTP server (hint: it almost certainly doesn't). - - Should be in the form of an HTTP origin: ws[s]://hostname[:port] - """ - ) - - mathjax_url = Unicode("", config=True, - help="""A custom url for MathJax.js. - Should be in the form of a case-sensitive url to MathJax, - for example: /static/components/MathJax/MathJax.js - """ - ) - - @default('mathjax_url') - def _default_mathjax_url(self): - if not self.enable_mathjax: - return u'' - static_url_prefix = self.tornado_settings.get("static_url_prefix", "static") - return url_path_join(static_url_prefix, 'components', 'MathJax', 'MathJax.js') - - @observe('mathjax_url') - def _update_mathjax_url(self, change): - new = change['new'] - if new and not self.enable_mathjax: - # enable_mathjax=False overrides mathjax_url - self.mathjax_url = u'' - else: - self.log.info(_("Using MathJax: %s"), new) - - mathjax_config = Unicode("TeX-AMS-MML_HTMLorMML-full,Safe", config=True, - help=_("""The MathJax.js configuration file that is to be used.""") - ) - - @observe('mathjax_config') - def _update_mathjax_config(self, change): - self.log.info(_("Using MathJax configuration file: %s"), change['new']) - - quit_button = Bool(True, config=True, - help="""If True, display a button in the dashboard to quit - (shutdown the notebook server).""" - ) - - # We relax this trait to handle Contents Managers using jupyter_server - # as the core backend. - contents_manager_class = TypeFromClasses( - default_value=LargeFileManager, - klasses=[ - ContentsManager, - # To make custom ContentsManagers both forward+backward - # compatible, we'll relax the strictness of this trait - # and allow jupyter_server contents managers to pass - # through. If jupyter_server is not installed, this class - # will be ignored. - 'jupyter_server.contents.services.managers.ContentsManager' - ], - config=True, - help=_('The notebook manager class to use.') - ) - - # Throws a deprecation warning to jupyter_server based contents managers. - @observe('contents_manager_class') - def _observe_contents_manager_class(self, change): - new = change['new'] - # If 'new' is a class, get a string representing the import - # module path. - if inspect.isclass(new): - new = new.__module__ - - if new.startswith('jupyter_server'): - self.log.warning( - "The specified 'contents_manager_class' class inherits a manager from the " - "'jupyter_server' package. These (future-looking) managers are not " - "guaranteed to work with the 'notebook' package. For longer term support " - "consider switching to NBClassic—a notebook frontend that leverages " - "Jupyter Server as its server backend." - ) - - kernel_manager_class = Type( - default_value=MappingKernelManager, - klass=MappingKernelManager, - config=True, - help=_('The kernel manager class to use.') - ) - - session_manager_class = Type( - default_value=SessionManager, - config=True, - help=_('The session manager class to use.') - ) - - config_manager_class = Type( - default_value=ConfigManager, - config = True, - help=_('The config manager class to use') - ) - - kernel_spec_manager = Instance(KernelSpecManager, allow_none=True) - - kernel_spec_manager_class = Type( - default_value=KernelSpecManager, - config=True, - help=""" - The kernel spec manager class to use. Should be a subclass - of `jupyter_client.kernelspec.KernelSpecManager`. - - The Api of KernelSpecManager is provisional and might change - without warning between this version of Jupyter and the next stable one. - """ - ) - - login_handler_class = Type( - default_value=LoginHandler, - klass=web.RequestHandler, - config=True, - help=_('The login handler class to use.'), - ) - - logout_handler_class = Type( - default_value=LogoutHandler, - klass=web.RequestHandler, - config=True, - help=_('The logout handler class to use.'), - ) - - trust_xheaders = Bool(False, config=True, - help=(_("Whether to trust or not X-Scheme/X-Forwarded-Proto and X-Real-Ip/X-Forwarded-For headers " - "sent by the upstream reverse proxy. Necessary if the proxy handles SSL")) - ) - - info_file = Unicode() - - @default('info_file') - def _default_info_file(self): - info_file = "nbserver-%s.json" % os.getpid() - return os.path.join(self.runtime_dir, info_file) - - browser_open_file = Unicode() - - @default('browser_open_file') - def _default_browser_open_file(self): - basename = "nbserver-%s-open.html" % os.getpid() - return os.path.join(self.runtime_dir, basename) - - pylab = Unicode('disabled', config=True, - help=_(""" - DISABLED: use %pylab or %matplotlib in the notebook to enable matplotlib. - """) - ) - - @observe('pylab') - def _update_pylab(self, change): - """when --pylab is specified, display a warning and exit""" - if change['new'] != 'warn': - backend = ' %s' % change['new'] - else: - backend = '' - self.log.error(_("Support for specifying --pylab on the command line has been removed.")) - self.log.error( - _("Please use `%pylab{0}` or `%matplotlib{0}` in the notebook itself.").format(backend) - ) - self.exit(1) - - notebook_dir = Unicode(config=True, - help=_("The directory to use for notebooks and kernels.") - ) - - @default('notebook_dir') - def _default_notebook_dir(self): - if self.file_to_run: - return os.path.dirname(os.path.abspath(self.file_to_run)) - else: - return py3compat.getcwd() - - @validate('notebook_dir') - def _notebook_dir_validate(self, proposal): - value = proposal['value'] - # Strip any trailing slashes - # *except* if it's root - _, path = os.path.splitdrive(value) - if path == os.sep: - return value - value = value.rstrip(os.sep) - if not os.path.isabs(value): - # If we receive a non-absolute path, make it absolute. - value = os.path.abspath(value) - if not os.path.isdir(value): - raise TraitError(trans.gettext("No such notebook dir: '%r'") % value) - return value - - # TODO: Remove me in notebook 5.0 - server_extensions = List(Unicode(), config=True, - help=(_("DEPRECATED use the nbserver_extensions dict instead")) - ) - - @observe('server_extensions') - def _update_server_extensions(self, change): - self.log.warning(_("server_extensions is deprecated, use nbserver_extensions")) - self.server_extensions = change['new'] - - nbserver_extensions = Dict({}, config=True, - help=(_("Dict of Python modules to load as notebook server extensions. " - "Entry values can be used to enable and disable the loading of " - "the extensions. The extensions will be loaded in alphabetical " - "order.")) - ) - - reraise_server_extension_failures = Bool( - False, - config=True, - help=_("Reraise exceptions encountered loading server extensions?"), - ) - - iopub_msg_rate_limit = Float(1000, config=True, help=_("""(msgs/sec) - Maximum rate at which messages can be sent on iopub before they are - limited.""")) - - iopub_data_rate_limit = Float(1000000, config=True, help=_("""(bytes/sec) - Maximum rate at which stream output can be sent on iopub before they are - limited.""")) - - rate_limit_window = Float(3, config=True, help=_("""(sec) Time window used to - check the message and data rate limits.""")) - - shutdown_no_activity_timeout = Integer(0, config=True, - help=("Shut down the server after N seconds with no kernels or " - "terminals running and no activity. " - "This can be used together with culling idle kernels " - "(MappingKernelManager.cull_idle_timeout) to " - "shutdown the notebook server when it's not in use. This is not " - "precisely timed: it may shut down up to a minute later. " - "0 (the default) disables this automatic shutdown.") - ) - - terminals_enabled = Bool(True, config=True, - help=_("""Set to False to disable terminals. - - This does *not* make the notebook server more secure by itself. - Anything the user can in a terminal, they can also do in a notebook. - - Terminals may also be automatically disabled if the terminado package - is not available. - """)) - - authenticate_prometheus = Bool( - True, - help="""" - Require authentication to access prometheus metrics. - """ - ).tag(config=True) - - @default('authenticate_prometheus') - def _default_authenticate_prometheus(self): - """ Authenticate Prometheus by default, unless auth is disabled. """ - auth = bool(self.password) or bool(self.token) - if auth is False: - self.log.info(_("Authentication of /metrics is OFF, since other authentication is disabled.")) - return auth - - @observe('authenticate_prometheus') - def _update_authenticate_prometheus(self, change): - newauth = change['new'] - if self.authenticate_prometheus is True and newauth is False: - self.log.info(_("Authentication of /metrics is being turned OFF.")) - self.authenticate_prometheus = newauth - - # Since use of terminals is also a function of whether the terminado package is - # available, this variable holds the "final indication" of whether terminal functionality - # should be considered (particularly during shutdown/cleanup). It is enabled only - # once both the terminals "service" can be initialized and terminals_enabled is True. - # Note: this variable is slightly different from 'terminals_available' in the web settings - # in that this variable *could* remain false if terminado is available, yet the terminal - # service's initialization still fails. As a result, this variable holds the truth. - terminals_available = False - - def parse_command_line(self, argv=None): - super().parse_command_line(argv) - - if self.extra_args: - arg0 = self.extra_args[0] - f = os.path.abspath(arg0) - self.argv.remove(arg0) - if not os.path.exists(f): - self.log.critical(_("No such file or directory: %s"), f) - self.exit(1) - - # Use config here, to ensure that it takes higher priority than - # anything that comes from the config dirs. - c = Config() - if os.path.isdir(f): - c.NotebookApp.notebook_dir = f - elif os.path.isfile(f): - c.NotebookApp.file_to_run = f - self.update_config(c) - - def init_configurables(self): - - # If gateway server is configured, replace appropriate managers to perform redirection. To make - # this determination, instantiate the GatewayClient config singleton. - self.gateway_config = GatewayClient.instance(parent=self) - - if self.gateway_config.gateway_enabled: - self.kernel_manager_class = 'notebook.gateway.managers.GatewayKernelManager' - self.session_manager_class = 'notebook.gateway.managers.GatewaySessionManager' - self.kernel_spec_manager_class = 'notebook.gateway.managers.GatewayKernelSpecManager' - - self.kernel_spec_manager = self.kernel_spec_manager_class( - parent=self, - ) - - self.kernel_manager = self.kernel_manager_class( - parent=self, - log=self.log, - connection_dir=self.runtime_dir, - kernel_spec_manager=self.kernel_spec_manager, - ) - # Ensure the appropriate version of Python and jupyter_client is available. - if isinstance(self.kernel_manager, AsyncMappingKernelManager): - if not async_kernel_mgmt_available: # Can be removed once jupyter_client >= 6.1 is required. - raise ValueError("You are using `AsyncMappingKernelManager` without an appropriate " - "jupyter_client installed! Please upgrade jupyter_client or change kernel managers.") - self.log.info("Asynchronous kernel management has been configured to use '{}'.". - format(self.kernel_manager.__class__.__name__)) - - self.contents_manager = self.contents_manager_class( - parent=self, - log=self.log, - ) - self.session_manager = self.session_manager_class( - parent=self, - log=self.log, - kernel_manager=self.kernel_manager, - contents_manager=self.contents_manager, - ) - self.config_manager = self.config_manager_class( - parent=self, - log=self.log, - ) - - def init_logging(self): - # This prevents double log messages because tornado use a root logger that - # self.log is a child of. The logging module dispatches log messages to a log - # and all of its ancenstors until propagate is set to False. - self.log.propagate = False - - for log in app_log, access_log, gen_log: - # consistent log output name (NotebookApp instead of tornado.access, etc.) - log.name = self.log.name - # hook up tornado 3's loggers to our app handlers - logger = logging.getLogger('tornado') - logger.propagate = True - logger.parent = self.log - logger.setLevel(self.log.level) - - def init_resources(self): - """initialize system resources""" - if resource is None: - self.log.debug('Ignoring min_open_files_limit because the limit cannot be adjusted (for example, on Windows)') - return - - old_soft, old_hard = resource.getrlimit(resource.RLIMIT_NOFILE) - soft = self.min_open_files_limit - hard = old_hard - if old_soft < soft: - if hard < soft: - hard = soft - self.log.debug( - 'Raising open file limit: soft {}->{}; hard {}->{}'.format(old_soft, soft, old_hard, hard) - ) - resource.setrlimit(resource.RLIMIT_NOFILE, (soft, hard)) - - def init_webapp(self): - """initialize tornado webapp and httpserver""" - self.tornado_settings['allow_origin'] = self.allow_origin - self.tornado_settings['websocket_compression_options'] = self.websocket_compression_options - if self.allow_origin_pat: - self.tornado_settings['allow_origin_pat'] = re.compile(self.allow_origin_pat) - self.tornado_settings['allow_credentials'] = self.allow_credentials - self.tornado_settings['autoreload'] = self.autoreload - self.tornado_settings['cookie_options'] = self.cookie_options - self.tornado_settings['get_secure_cookie_kwargs'] = self.get_secure_cookie_kwargs - self.tornado_settings['token'] = self.token - - # ensure default_url starts with base_url - if not self.default_url.startswith(self.base_url): - self.default_url = url_path_join(self.base_url, self.default_url) - - if self.password_required and (not self.password): - self.log.critical(_("Notebook servers are configured to only be run with a password.")) - self.log.critical(_("Hint: run the following command to set a password")) - self.log.critical(_("\t$ python -m notebook.auth password")) - sys.exit(1) - - # Socket options validation. - if self.sock: - if self.port != DEFAULT_NOTEBOOK_PORT: - self.log.critical( - _('Options --port and --sock are mutually exclusive. Aborting.'), - ) - sys.exit(1) - else: - # Reset the default port if we're using a UNIX socket. - self.port = 0 - - if self.open_browser: - # If we're bound to a UNIX socket, we can't reliably connect from a browser. - self.log.info( - _('Ignoring --NotebookApp.open_browser due to --sock being used.'), - ) - - if self.file_to_run: - self.log.critical( - _('Options --NotebookApp.file_to_run and --sock are mutually exclusive.'), - ) - sys.exit(1) - - if sys.platform.startswith('win'): - self.log.critical( - _('Option --sock is not supported on Windows, but got value of %s. Aborting.' % self.sock), - ) - sys.exit(1) - - self.web_app = NotebookWebApplication( - self, self.kernel_manager, self.contents_manager, - self.session_manager, self.kernel_spec_manager, - self.config_manager, self.extra_services, - self.log, self.base_url, self.default_url, self.tornado_settings, - self.jinja_environment_options, - ) - ssl_options = self.ssl_options - if self.certfile: - ssl_options['certfile'] = self.certfile - if self.keyfile: - ssl_options['keyfile'] = self.keyfile - if self.client_ca: - ssl_options['ca_certs'] = self.client_ca - if not ssl_options: - # None indicates no SSL config - ssl_options = None - else: - # SSL may be missing, so only import it if it's to be used - import ssl - # PROTOCOL_TLS selects the highest ssl/tls protocol version that both the client and - # server support. When PROTOCOL_TLS is not available use PROTOCOL_SSLv23. - # PROTOCOL_TLS is new in version 2.7.13, 3.5.3 and 3.6 - ssl_options.setdefault( - 'ssl_version', - getattr(ssl, 'PROTOCOL_TLS', ssl.PROTOCOL_SSLv23) - ) - if ssl_options.get('ca_certs', False): - ssl_options.setdefault('cert_reqs', ssl.CERT_REQUIRED) - - self.login_handler_class.validate_security(self, ssl_options=ssl_options) - self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options, - xheaders=self.trust_xheaders, - max_body_size=self.max_body_size, - max_buffer_size=self.max_buffer_size) - - def _bind_http_server(self): - return self._bind_http_server_unix() if self.sock else self._bind_http_server_tcp() - - def _bind_http_server_unix(self): - if unix_socket_in_use(self.sock): - self.log.warning(_('The socket %s is already in use.') % self.sock) - return False - - try: - sock = bind_unix_socket(self.sock, mode=int(self.sock_mode.encode(), 8)) - self.http_server.add_socket(sock) - except socket.error as e: - if e.errno == errno.EADDRINUSE: - self.log.warning(_('The socket %s is already in use.') % self.sock) - return False - elif e.errno in (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)): - self.log.warning(_("Permission to listen on sock %s denied") % self.sock) - return False - else: - raise - else: - return True - - def _bind_http_server_tcp(self): - success = None - for port in random_ports(self.port, self.port_retries+1): - try: - self.http_server.listen(port, self.ip) - except socket.error as e: - eacces = (errno.EACCES, getattr(errno, 'WSAEACCES', errno.EACCES)) - if sys.platform == 'cygwin': - # Cygwin has a bug that causes EPERM to be returned in this - # case instead of EACCES: - # https://cygwin.com/ml/cygwin/2019-04/msg00160.html - eacces += (errno.EPERM,) - - if e.errno == errno.EADDRINUSE: - if self.port_retries: - self.log.info(_('The port %i is already in use, trying another port.') % port) - else: - self.log.info(_('The port %i is already in use.') % port) - continue - elif e.errno in eacces: - self.log.warning(_("Permission to listen on port %i denied.") % port) - continue - else: - raise - else: - self.port = port - success = True - break - if not success: - if self.port_retries: - self.log.critical(_('ERROR: the notebook server could not be started because ' - 'no available port could be found.')) - else: - self.log.critical(_('ERROR: the notebook server could not be started because ' - 'port %i is not available.') % port) - self.exit(1) - return success - - def _concat_token(self, url): - token = self.token if self._token_generated else '...' - return url_concat(url, {'token': token}) - - @property - def display_url(self): - if self.custom_display_url: - url = self.custom_display_url - if not url.endswith('/'): - url += '/' - elif self.sock: - url = self._unix_sock_url() - else: - if self.ip in ('', '0.0.0.0'): - ip = "%s" % socket.gethostname() - else: - ip = self.ip - url = self._tcp_url(ip) - if self.token and not self.sock: - url = self._concat_token(url) - if not self.custom_display_url: - url += '\n or %s' % self._concat_token(self._tcp_url('127.0.0.1')) - return url - - @property - def connection_url(self): - if self.sock: - return self._unix_sock_url() - else: - ip = self.ip if self.ip else 'localhost' - return self._tcp_url(ip) - - def _unix_sock_url(self, token=None): - return '%s%s' % (urlencode_unix_socket(self.sock), self.base_url) - - def _tcp_url(self, ip, port=None): - proto = 'https' if self.certfile else 'http' - return "%s://%s:%i%s" % (proto, ip, port or self.port, self.base_url) - - def init_terminals(self): - if not self.terminals_enabled: - return - - try: - from .terminal import initialize - initialize(nb_app=self) - self.terminals_available = True - except ImportError as e: - self.log.warning(_("Terminals not available (error was %s)"), e) - - def init_signal(self): - if not sys.platform.startswith('win') and sys.stdin and sys.stdin.isatty(): - signal.signal(signal.SIGINT, self._handle_sigint) - signal.signal(signal.SIGTERM, self._signal_stop) - if hasattr(signal, 'SIGUSR1'): - # Windows doesn't support SIGUSR1 - signal.signal(signal.SIGUSR1, self._signal_info) - if hasattr(signal, 'SIGINFO'): - # only on BSD-based systems - signal.signal(signal.SIGINFO, self._signal_info) - - def _handle_sigint(self, sig, frame): - """SIGINT handler spawns confirmation dialog""" - # register more forceful signal handler for ^C^C case - signal.signal(signal.SIGINT, self._signal_stop) - # request confirmation dialog in bg thread, to avoid - # blocking the App - thread = threading.Thread(target=self._confirm_exit) - thread.daemon = True - thread.start() - - def _restore_sigint_handler(self): - """callback for restoring original SIGINT handler""" - signal.signal(signal.SIGINT, self._handle_sigint) - - def _confirm_exit(self): - """confirm shutdown on ^C - - A second ^C, or answering 'y' within 5s will cause shutdown, - otherwise original SIGINT handler will be restored. - - This doesn't work on Windows. - """ - info = self.log.info - info(_('interrupted')) - # Check if answer_yes is set - if self.answer_yes: - self.log.critical(_("Shutting down...")) - # schedule stop on the main thread, - # since this might be called from a signal handler - self.io_loop.add_callback_from_signal(self.io_loop.stop) - return - print(self.notebook_info()) - yes = _('y') - no = _('n') - sys.stdout.write(_("Shutdown this notebook server (%s/[%s])? ") % (yes, no)) - sys.stdout.flush() - r,w,x = select.select([sys.stdin], [], [], 5) - if r: - line = sys.stdin.readline() - if line.lower().startswith(yes) and no not in line.lower(): - self.log.critical(_("Shutdown confirmed")) - # schedule stop on the main thread, - # since this might be called from a signal handler - self.io_loop.add_callback_from_signal(self.io_loop.stop) - return - else: - print(_("No answer for 5s:"), end=' ') - print(_("resuming operation...")) - # no answer, or answer is no: - # set it back to original SIGINT handler - # use IOLoop.add_callback because signal.signal must be called - # from main thread - self.io_loop.add_callback_from_signal(self._restore_sigint_handler) - - def _signal_stop(self, sig, frame): - self.log.critical(_("received signal %s, stopping"), sig) - self.io_loop.add_callback_from_signal(self.io_loop.stop) - - def _signal_info(self, sig, frame): - print(self.notebook_info()) - - def init_components(self): - """Check the components submodule, and warn if it's unclean""" - # TODO: this should still check, but now we use bower, not git submodule - pass - - def init_server_extension_config(self): - """Consolidate server extensions specified by all configs. - - The resulting list is stored on self.nbserver_extensions and updates config object. - - The extension API is experimental, and may change in future releases. - """ - # TODO: Remove me in notebook 5.0 - for modulename in self.server_extensions: - # Don't override disable state of the extension if it already exist - # in the new traitlet - if not modulename in self.nbserver_extensions: - self.nbserver_extensions[modulename] = True - - # Load server extensions with ConfigManager. - # This enables merging on keys, which we want for extension enabling. - # Regular config loading only merges at the class level, - # so each level (user > env > system) clobbers the previous. - config_path = jupyter_config_path() - if self.config_dir not in config_path: - # add self.config_dir to the front, if set manually - config_path.insert(0, self.config_dir) - manager = ConfigManager(read_config_path=config_path) - section = manager.get(self.config_file_name) - extensions = section.get('NotebookApp', {}).get('nbserver_extensions', {}) - - for modulename, enabled in sorted(extensions.items()): - if modulename not in self.nbserver_extensions: - self.config.NotebookApp.nbserver_extensions.update({modulename: enabled}) - self.nbserver_extensions.update({modulename: enabled}) - - def init_server_extensions(self): - """Load any extensions specified by config. - - Import the module, then call the load_jupyter_server_extension function, - if one exists. - - The extension API is experimental, and may change in future releases. - """ - - - for modulename, enabled in sorted(self.nbserver_extensions.items()): - if enabled: - try: - mod = importlib.import_module(modulename) - func = getattr(mod, 'load_jupyter_server_extension', None) - if func is not None: - func(self) - except Exception: - if self.reraise_server_extension_failures: - raise - self.log.warning(_("Error loading server extension %s"), modulename, - exc_info=True) - - def init_mime_overrides(self): - # On some Windows machines, an application has registered incorrect - # mimetypes in the registry. - # Tornado uses this when serving .css and .js files, causing browsers to - # reject these files. We know the mimetype always needs to be text/css for css - # and application/javascript for JS, so we override it here - # and explicitly tell the mimetypes to not trust the Windows registry - if os.name == 'nt': - # do not trust windows registry, which regularly has bad info - mimetypes.init(files=[]) - # ensure css, js are correct, which are required for pages to function - mimetypes.add_type('text/css', '.css') - mimetypes.add_type('application/javascript', '.js') - # for python <3.8 - mimetypes.add_type('application/wasm', '.wasm') - - def shutdown_no_activity(self): - """Shutdown server on timeout when there are no kernels or terminals.""" - km = self.kernel_manager - if len(km) != 0: - return # Kernels still running - - if self.terminals_available: - term_mgr = self.web_app.settings['terminal_manager'] - if term_mgr.terminals: - return # Terminals still running - - seconds_since_active = \ - (utcnow() - self.web_app.last_activity()).total_seconds() - self.log.debug("No activity for %d seconds.", - seconds_since_active) - if seconds_since_active > self.shutdown_no_activity_timeout: - self.log.info("No kernels or terminals for %d seconds; shutting down.", - seconds_since_active) - self.stop() - - def init_shutdown_no_activity(self): - if self.shutdown_no_activity_timeout > 0: - self.log.info("Will shut down after %d seconds with no kernels or terminals.", - self.shutdown_no_activity_timeout) - pc = ioloop.PeriodicCallback(self.shutdown_no_activity, 60000) - pc.start() - - def _init_asyncio_patch(self): - """set default asyncio policy to be compatible with tornado - - Tornado 6 (at least) is not compatible with the default - asyncio implementation on Windows - - Pick the older SelectorEventLoopPolicy on Windows - if the known-incompatible default policy is in use. - - do this as early as possible to make it a low priority and overrideable - - ref: https://github.com/tornadoweb/tornado/issues/2608 - - FIXME: if/when tornado supports the defaults in asyncio, - remove and bump tornado requirement for py38 - - With the introduction of the async kernel, the existing sync kernel - requires the use of nested loops in order to run code synchronously. - This is done in `jupyter_client` using the helper util `run_sync`: - - ref: https://github.com/jupyter/jupyter_client/blob/f453b51eeeff9e905c583b7da3905c0e35cfbdf0/jupyter_client/utils.py#L11 - - which creates a new event loop and relies on `nest_asyncio` patching - to allow nested loops. This requires that *all* potential tasks are - patched before executing. When only some tasks are patched it leads to - the following issue: - - ref: https://github.com/jupyter/notebook/issues/6164 - - So we must call `nest_asyncio.apply()` method as early as possible. It - is preferable to do this in the consuming application rather than the - `jupyter_client` as it is a global patch and would impact all consumers - rather than just the ones that rely on synchronous kernel behavior. - """ - import nest_asyncio - - try: - nest_asyncio.apply() - except RuntimeError: - # nest_asyncio requires a running loop in order to patch. - # In tests the loop may not have been created yet. - pass - - if sys.platform.startswith("win") and sys.version_info >= (3, 8): - import asyncio - try: - from asyncio import ( - WindowsProactorEventLoopPolicy, - WindowsSelectorEventLoopPolicy, - ) - except ImportError: - pass - # not affected - else: - if type(asyncio.get_event_loop_policy()) is WindowsProactorEventLoopPolicy: - # WindowsProactorEventLoopPolicy is not compatible with tornado 6 - # fallback to the pre-3.8 default of Selector - asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy()) - - @catch_config_error - def initialize(self, argv=None): - self._init_asyncio_patch() - - super().initialize(argv) - self.init_logging() - if self._dispatching: - return - self.init_resources() - self.init_configurables() - self.init_server_extension_config() - self.init_components() - self.init_webapp() - self.init_terminals() - self.init_signal() - self.init_server_extensions() - self.init_mime_overrides() - self.init_shutdown_no_activity() - - def cleanup_kernels(self): - """Shutdown all kernels. - - The kernels will shutdown themselves when this process no longer exists, - but explicit shutdown allows the KernelManagers to cleanup the connection files. - """ - n_kernels = len(self.kernel_manager.list_kernel_ids()) - kernel_msg = trans.ngettext('Shutting down %d kernel', 'Shutting down %d kernels', n_kernels) - self.log.info(kernel_msg % n_kernels) - run_sync(self.kernel_manager.shutdown_all()) - - def cleanup_terminals(self): - """Shutdown all terminals. - - The terminals will shutdown themselves when this process no longer exists, - but explicit shutdown allows the TerminalManager to cleanup. - """ - if not self.terminals_available: - return - - terminal_manager = self.web_app.settings['terminal_manager'] - n_terminals = len(terminal_manager.list()) - terminal_msg = trans.ngettext('Shutting down %d terminal', 'Shutting down %d terminals', n_terminals) - self.log.info(terminal_msg % n_terminals) - run_sync(terminal_manager.terminate_all()) - - def notebook_info(self, kernel_count=True): - "Return the current working directory and the server url information" - info = self.contents_manager.info_string() + "\n" - if kernel_count: - n_kernels = len(self.kernel_manager.list_kernel_ids()) - kernel_msg = trans.ngettext("%d active kernel", "%d active kernels", n_kernels) - info += kernel_msg % n_kernels - info += "\n" - # Format the info so that the URL fits on a single line in 80 char display - info += _("Jupyter Notebook {version} is running at:\n{url}". - format(version=NotebookApp.version, url=self.display_url)) - if self.gateway_config.gateway_enabled: - info += _("\nKernels will be managed by the Gateway server running at:\n%s") % self.gateway_config.url - return info - - def server_info(self): - """Return a JSONable dict of information about this server.""" - return {'url': self.connection_url, - 'hostname': self.ip if self.ip else 'localhost', - 'port': self.port, - 'sock': self.sock, - 'secure': bool(self.certfile), - 'base_url': self.base_url, - 'token': self.token, - 'notebook_dir': os.path.abspath(self.notebook_dir), - 'password': bool(self.password), - 'pid': os.getpid(), - } - - def write_server_info_file(self): - """Write the result of server_info() to the JSON file info_file.""" - try: - with open(self.info_file, 'w') as f: - json.dump(self.server_info(), f, indent=2, sort_keys=True) - except OSError as e: - self.log.error(_("Failed to write server-info to %s: %s"), - self.info_file, e) - - def remove_server_info_file(self): - """Remove the nbserver-.json file created for this server. - - Ignores the error raised when the file has already been removed. - """ - try: - os.unlink(self.info_file) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - def write_browser_open_file(self): - """Write an nbserver--open.html file - - This can be used to open the notebook in a browser - """ - # default_url contains base_url, but so does connection_url - open_url = self.default_url[len(self.base_url):] - - with open(self.browser_open_file, 'w', encoding='utf-8') as f: - self._write_browser_open_file(open_url, f) - - def _write_browser_open_file(self, url, fh): - if self.token: - url = url_concat(url, {'token': self.token}) - url = url_path_join(self.connection_url, url) - - jinja2_env = self.web_app.settings['jinja2_env'] - template = jinja2_env.get_template('browser-open.html') - fh.write(template.render(open_url=url)) - - def remove_browser_open_file(self): - """Remove the nbserver--open.html file created for this server. - - Ignores the error raised when the file has already been removed. - """ - try: - os.unlink(self.browser_open_file) - except OSError as e: - if e.errno != errno.ENOENT: - raise - - def launch_browser(self): - try: - browser = webbrowser.get(self.browser or None) - except webbrowser.Error as e: - self.log.warning(_('No web browser found: %s.') % e) - browser = None - - if not browser: - return - - if not self.use_redirect_file: - uri = self.default_url[len(self.base_url):] - - if self.token: - uri = url_concat(uri, {'token': self.token}) - - if self.file_to_run: - if not os.path.exists(self.file_to_run): - self.log.critical(_("%s does not exist") % self.file_to_run) - self.exit(1) - - relpath = os.path.relpath(self.file_to_run, self.notebook_dir) - uri = url_escape(url_path_join('notebooks', *relpath.split(os.sep))) - - # Write a temporary file to open in the browser - fd, open_file = tempfile.mkstemp(suffix='.html') - with open(fd, 'w', encoding='utf-8') as fh: - self._write_browser_open_file(uri, fh) - else: - open_file = self.browser_open_file - - if self.use_redirect_file: - assembled_url = urljoin('file:', pathname2url(open_file)) - else: - assembled_url = url_path_join(self.connection_url, uri) - - b = lambda: browser.open(assembled_url, new=self.webbrowser_open_new) - threading.Thread(target=b).start() - - def start(self): - """ Start the Notebook server app, after initialization - - This method takes no arguments so all configuration and initialization - must be done prior to calling this method.""" - - super().start() - - if not self.allow_root: - # check if we are running as root, and abort if it's not allowed - try: - uid = os.geteuid() - except AttributeError: - uid = -1 # anything nonzero here, since we can't check UID assume non-root - if uid == 0: - self.log.critical(_("Running as root is not recommended. Use --allow-root to bypass.")) - self.exit(1) - - success = self._bind_http_server() - if not success: - self.log.critical(_('ERROR: the notebook server could not be started because ' - 'no available port could be found.')) - self.exit(1) - - info = self.log.info - for line in self.notebook_info(kernel_count=False).split("\n"): - info(line) - info(_("Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).")) - if 'dev' in notebook.__version__: - info(_("Welcome to Project Jupyter! Explore the various tools available" - " and their corresponding documentation. If you are interested" - " in contributing to the platform, please visit the community" - "resources section at https://jupyter.org/community.html.")) - - self.write_server_info_file() - self.write_browser_open_file() - - if (self.open_browser or self.file_to_run) and not self.sock: - self.launch_browser() - - if self.token and self._token_generated: - # log full URL with generated token, so there's a copy/pasteable link - # with auth info. - if self.sock: - self.log.critical('\n'.join([ - '\n', - 'Notebook is listening on %s' % self.display_url, - '', - ( - 'UNIX sockets are not browser-connectable, but you can tunnel to ' - 'the instance via e.g.`ssh -L 8888:%s -N user@this_host` and then ' - 'open e.g. %s in a browser.' - ) % (self.sock, self._concat_token(self._tcp_url('localhost', 8888))) - ])) - else: - if not self.custom_display_url: - self.log.critical('\n'.join([ - '\n', - 'To access the notebook, open this file in a browser:', - ' %s' % urljoin('file:', pathname2url(self.browser_open_file)), - 'Or copy and paste one of these URLs:', - ' %s' % self.display_url, - ])) - else: - self.log.critical('\n'.join([ - '\n', - 'To access the notebook, open this file in a browser:', - ' %s' % urljoin('file:', pathname2url(self.browser_open_file)), - 'Or copy and paste this URL:', - ' %s' % self.display_url, - ])) - - self.io_loop = ioloop.IOLoop.current() - if sys.platform.startswith('win'): - # add no-op to wake every 5s - # to handle signals that may be ignored by the inner loop - pc = ioloop.PeriodicCallback(lambda : None, 5000) - pc.start() - try: - self.io_loop.start() - except KeyboardInterrupt: - info(_("Interrupted...")) - finally: - self.remove_server_info_file() - self.remove_browser_open_file() - self.cleanup_kernels() - self.cleanup_terminals() - - def stop(self): - def _stop(): - self.http_server.stop() - self.io_loop.stop() - self.io_loop.add_callback(_stop) - - -def list_running_servers(runtime_dir=None): - """Iterate over the server info files of running notebook servers. - - Given a runtime directory, find nbserver-* files in the security directory, - and yield dicts of their information, each one pertaining to - a currently running notebook server instance. - """ - if runtime_dir is None: - runtime_dir = jupyter_runtime_dir() - - # The runtime dir might not exist - if not os.path.isdir(runtime_dir): - return - - for file_name in os.listdir(runtime_dir): - if re.match('nbserver-(.+).json', file_name): - with io.open(os.path.join(runtime_dir, file_name), encoding='utf-8') as f: - info = json.load(f) - - # Simple check whether that process is really still running - # Also remove leftover files from IPython 2.x without a pid field - if ('pid' in info) and check_pid(info['pid']): - yield info - else: - # If the process has died, try to delete its info file - try: - os.unlink(os.path.join(runtime_dir, file_name)) - except OSError: - pass # TODO: This should warn or log or something -#----------------------------------------------------------------------------- -# Main entry point -#----------------------------------------------------------------------------- - -main = launch_new_instance = NotebookApp.launch_instance diff --git a/notebook/prometheus/__init__.py b/notebook/prometheus/__init__.py deleted file mode 100644 index c63c130a1..000000000 --- a/notebook/prometheus/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -""" -A package containing all the functionality and -configuration connected to the prometheus metrics -""" \ No newline at end of file diff --git a/notebook/prometheus/log_functions.py b/notebook/prometheus/log_functions.py deleted file mode 100644 index a67a252ad..000000000 --- a/notebook/prometheus/log_functions.py +++ /dev/null @@ -1,24 +0,0 @@ -from ..prometheus.metrics import HTTP_REQUEST_DURATION_SECONDS - - -def prometheus_log_method(handler): - """ - Tornado log handler for recording RED metrics. - - We record the following metrics: - Rate - the number of requests, per second, your services are serving. - Errors - the number of failed requests per second. - Duration - The amount of time each request takes expressed as a time interval. - - We use a fully qualified name of the handler as a label, - rather than every url path to reduce cardinality. - - This function should be either the value of or called from a function - that is the 'log_function' tornado setting. This makes it get called - at the end of every request, allowing us to record the metrics we need. - """ - HTTP_REQUEST_DURATION_SECONDS.labels( - method=handler.request.method, - handler='{}.{}'.format(handler.__class__.__module__, type(handler).__name__), - status_code=handler.get_status() - ).observe(handler.request.request_time()) diff --git a/notebook/prometheus/metrics.py b/notebook/prometheus/metrics.py deleted file mode 100644 index abc9d0e16..000000000 --- a/notebook/prometheus/metrics.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Prometheus metrics exported by Jupyter Notebook Server - -Read https://prometheus.io/docs/practices/naming/ for naming -conventions for metrics & labels. -""" - - -from prometheus_client import Histogram, Gauge - - -HTTP_REQUEST_DURATION_SECONDS = Histogram( - 'http_request_duration_seconds', - 'duration in seconds for all HTTP requests', - ['method', 'handler', 'status_code'], -) - -TERMINAL_CURRENTLY_RUNNING_TOTAL = Gauge( - 'terminal_currently_running_total', - 'counter for how many terminals are running', -) - -KERNEL_CURRENTLY_RUNNING_TOTAL = Gauge( - 'kernel_currently_running_total', - 'counter for how many kernels are running labeled by type', - ['type'] -) diff --git a/notebook/serverextensions.py b/notebook/serverextensions.py deleted file mode 100644 index 72020a24f..000000000 --- a/notebook/serverextensions.py +++ /dev/null @@ -1,331 +0,0 @@ -"""Utilities for installing server extensions for the notebook""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import importlib -import sys - -from jupyter_core.paths import jupyter_config_path -from ._version import __version__ -from .config_manager import BaseJSONConfigManager -from .extensions import ( - BaseExtensionApp, _get_config_dir, GREEN_ENABLED, RED_DISABLED, GREEN_OK, RED_X -) -from traitlets import Bool -from traitlets.utils.importstring import import_item - - -# ------------------------------------------------------------------------------ -# Public API -# ------------------------------------------------------------------------------ - -def toggle_serverextension_python(import_name, enabled=None, parent=None, - user=True, sys_prefix=False, logger=None): - """Toggle a server extension. - - By default, toggles the extension in the system-wide Jupyter configuration - location (e.g. /usr/local/etc/jupyter). - - Parameters - ---------- - - import_name : str - Importable Python module (dotted-notation) exposing the magic-named - `load_jupyter_server_extension` function - enabled : bool [default: None] - Toggle state for the extension. Set to None to toggle, True to enable, - and False to disable the extension. - parent : Configurable [default: None] - user : bool [default: True] - Toggle in the user's configuration location (e.g. ~/.jupyter). - sys_prefix : bool [default: False] - Toggle in the current Python environment's configuration location - (e.g. ~/.envs/my-env/etc/jupyter). Will override `user`. - logger : Jupyter logger [optional] - Logger instance to use - """ - user = False if sys_prefix else user - config_dir = _get_config_dir(user=user, sys_prefix=sys_prefix) - cm = BaseJSONConfigManager(parent=parent, config_dir=config_dir) - cfg = cm.get("jupyter_notebook_config") - server_extensions = ( - cfg.setdefault("NotebookApp", {}) - .setdefault("nbserver_extensions", {}) - ) - - old_enabled = server_extensions.get(import_name, None) - new_enabled = enabled if enabled is not None else not old_enabled - - if logger: - if new_enabled: - logger.info(u"Enabling: %s" % (import_name)) - else: - logger.info(u"Disabling: %s" % (import_name)) - - server_extensions[import_name] = new_enabled - - if logger: - logger.info(u"- Writing config: {}".format(config_dir)) - - cm.update("jupyter_notebook_config", cfg) - - if new_enabled: - validate_serverextension(import_name, logger) - - -def validate_serverextension(import_name, logger=None): - """Assess the health of an installed server extension - - Returns a list of validation warnings. - - Parameters - ---------- - - import_name : str - Importable Python module (dotted-notation) exposing the magic-named - `load_jupyter_server_extension` function - logger : Jupyter logger [optional] - Logger instance to use - """ - - warnings = [] - infos = [] - - func = None - - if logger: - logger.info(" - Validating...") - - try: - mod = importlib.import_module(import_name) - func = getattr(mod, 'load_jupyter_server_extension', None) - version = getattr(mod, '__version__', '') - except Exception: - logger.warning("Error loading server extension %s", import_name) - - import_msg = u" {} is {} importable?" - if func is not None: - infos.append(import_msg.format(GREEN_OK, import_name)) - else: - warnings.append(import_msg.format(RED_X, import_name)) - - post_mortem = u" {} {} {}" - if logger: - if warnings: - [logger.info(info) for info in infos] - [logger.warn(warning) for warning in warnings] - else: - logger.info(post_mortem.format(import_name, version, GREEN_OK)) - - return warnings - - -# ---------------------------------------------------------------------- -# Applications -# ---------------------------------------------------------------------- - -flags = {} -flags.update(BaseExtensionApp.flags) -flags.pop("y", None) -flags.pop("generate-config", None) -flags.update({ - "user" : ({ - "ToggleServerExtensionApp" : { - "user" : True, - }}, "Perform the operation for the current user" - ), - "system" : ({ - "ToggleServerExtensionApp" : { - "user" : False, - "sys_prefix": False, - }}, "Perform the operation system-wide" - ), - "sys-prefix" : ({ - "ToggleServerExtensionApp" : { - "sys_prefix" : True, - }}, "Use sys.prefix as the prefix for installing server extensions" - ), - "py" : ({ - "ToggleServerExtensionApp" : { - "python" : True, - }}, "Install from a Python package" - ), -}) -flags['python'] = flags['py'] - - -class ToggleServerExtensionApp(BaseExtensionApp): - """A base class for enabling/disabling extensions""" - name = "jupyter serverextension enable/disable" - description = "Enable/disable a server extension using frontend configuration files." - - flags = flags - - user = Bool(True, config=True, help="Whether to do a user install") - sys_prefix = Bool(False, config=True, help="Use the sys.prefix as the prefix") - python = Bool(False, config=True, help="Install from a Python package") - - def toggle_server_extension(self, import_name): - """Change the status of a named server extension. - - Uses the value of `self._toggle_value`. - - Parameters - --------- - - import_name : str - Importable Python module (dotted-notation) exposing the magic-named - `load_jupyter_server_extension` function - """ - toggle_serverextension_python( - import_name, self._toggle_value, parent=self, user=self.user, - sys_prefix=self.sys_prefix, logger=self.log) - - def toggle_server_extension_python(self, package): - """Change the status of some server extensions in a Python package. - - Uses the value of `self._toggle_value`. - - Parameters - --------- - - package : str - Importable Python module exposing the - magic-named `_jupyter_server_extension_paths` function - """ - m, server_exts = _get_server_extension_metadata(package) - for server_ext in server_exts: - module = server_ext['module'] - self.toggle_server_extension(module) - - def start(self): - """Perform the App's actions as configured""" - if not self.extra_args: - sys.exit('Please specify a server extension/package to enable or disable') - for arg in self.extra_args: - if self.python: - self.toggle_server_extension_python(arg) - else: - self.toggle_server_extension(arg) - - -class EnableServerExtensionApp(ToggleServerExtensionApp): - """An App that enables (and validates) Server Extensions""" - name = "jupyter serverextension enable" - description = """ - Enable a serverextension in configuration. - - Usage - jupyter serverextension enable [--system|--sys-prefix] - """ - _toggle_value = True - - -class DisableServerExtensionApp(ToggleServerExtensionApp): - """An App that disables Server Extensions""" - name = "jupyter serverextension disable" - description = """ - Disable a serverextension in configuration. - - Usage - jupyter serverextension disable [--system|--sys-prefix] - """ - _toggle_value = False - - -class ListServerExtensionsApp(BaseExtensionApp): - """An App that lists (and validates) Server Extensions""" - name = "jupyter serverextension list" - version = __version__ - description = "List all server extensions known by the configuration system" - - def list_server_extensions(self): - """List all enabled and disabled server extensions, by config path - - Enabled extensions are validated, potentially generating warnings. - """ - config_dirs = jupyter_config_path() - for config_dir in config_dirs: - cm = BaseJSONConfigManager(parent=self, config_dir=config_dir) - data = cm.get("jupyter_notebook_config") - server_extensions = ( - data.setdefault("NotebookApp", {}) - .setdefault("nbserver_extensions", {}) - ) - if server_extensions: - print(u'config dir: {}'.format(config_dir)) - for import_name, enabled in server_extensions.items(): - print(u' {} {}'.format( - import_name, - GREEN_ENABLED if enabled else RED_DISABLED)) - validate_serverextension(import_name, self.log) - - def start(self): - """Perform the App's actions as configured""" - self.list_server_extensions() - - -_examples = """ -jupyter serverextension list # list all configured server extensions -jupyter serverextension enable --py # enable all server extensions in a Python package -jupyter serverextension disable --py # disable all server extensions in a Python package -""" - - -class ServerExtensionApp(BaseExtensionApp): - """Root level server extension app""" - name = "jupyter serverextension" - version = __version__ - description = "Work with Jupyter server extensions" - examples = _examples - - subcommands = dict( - enable=(EnableServerExtensionApp, "Enable a server extension"), - disable=(DisableServerExtensionApp, "Disable a server extension"), - list=(ListServerExtensionsApp, "List server extensions") - ) - - def start(self): - """Perform the App's actions as configured""" - super().start() - - # The above should have called a subcommand and raised NoStart; if we - # get here, it didn't, so we should self.log.info a message. - subcmds = ", ".join(sorted(self.subcommands)) - sys.exit("Please supply at least one subcommand: %s" % subcmds) - - -main = ServerExtensionApp.launch_instance - -# ------------------------------------------------------------------------------ -# Private API -# ------------------------------------------------------------------------------ - - -def _get_server_extension_metadata(module): - """Load server extension metadata from a module. - - Returns a tuple of ( - the package as loaded - a list of server extension specs: [ - { - "module": "mockextension" - } - ] - ) - - Parameters - ---------- - - module : str - Importable Python module exposing the - magic-named `_jupyter_server_extension_paths` function - """ - m = import_item(module) - if not hasattr(m, '_jupyter_server_extension_paths'): - raise KeyError(u'The Python module {} does not include any valid server extensions'.format(module)) - return m, m._jupyter_server_extension_paths() - -if __name__ == '__main__': - main() diff --git a/notebook/services/__init__.py b/notebook/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/api/__init__.py b/notebook/services/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/api/api.yaml b/notebook/services/api/api.yaml deleted file mode 100644 index a478597c2..000000000 --- a/notebook/services/api/api.yaml +++ /dev/null @@ -1,857 +0,0 @@ -swagger: '2.0' -info: - title: Jupyter Notebook API - description: Notebook API - version: "5" - contact: - name: Jupyter Project - url: https://jupyter.org -# will be prefixed to all paths -basePath: / -produces: - - application/json -consumes: - - application/json -parameters: - kernel: - name: kernel_id - required: true - in: path - description: kernel uuid - type: string - format: uuid - session: - name: session - required: true - in: path - description: session uuid - type: string - format: uuid - path: - name: path - required: true - in: path - description: file path - type: string - checkpoint_id: - name: checkpoint_id - required: true - in: path - description: Checkpoint id for a file - type: string - section_name: - name: section_name - required: true - in: path - description: Name of config section - type: string - terminal_id: - name: terminal_id - required: true - in: path - description: ID of terminal session - type: string - -paths: - - - /api/contents/{path}: - parameters: - - $ref: '#/parameters/path' - get: - summary: Get contents of file or directory - description: "A client can optionally specify a type and/or format argument via URL parameter. When given, the Contents service shall return a model in the requested type and/or format. If the request cannot be satisfied, e.g. type=text is requested, but the file is binary, then the request shall fail with 400 and have a JSON response containing a 'reason' field, with the value 'bad format' or 'bad type', depending on what was requested." - tags: - - contents - parameters: - - name: type - in: query - description: File type ('file', 'directory') - type: string - enum: - - file - - directory - - name: format - in: query - description: "How file content should be returned ('text', 'base64')" - type: string - enum: - - text - - base64 - - name: content - in: query - description: "Return content (0 for no content, 1 for return content)" - type: integer - responses: - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - 200: - description: Contents of file or directory - headers: - Last-Modified: - description: Last modified date for file - type: string - format: dateTime - schema: - $ref: '#/definitions/Contents' - 500: - description: Model key error - post: - summary: Create a new file in the specified path - description: "A POST to /api/contents/path creates a New untitled, empty file or directory. A POST to /api/contents/path with body {'copy_from': '/path/to/OtherNotebook.ipynb'} creates a new copy of OtherNotebook in path." - tags: - - contents - parameters: - - name: model - in: body - description: Path of file to copy - schema: - type: object - properties: - copy_from: - type: string - ext: - type: string - type: - type: string - responses: - 201: - description: File created - headers: - Location: - description: URL for the new file - type: string - format: url - schema: - $ref: '#/definitions/Contents' - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - patch: - summary: Rename a file or directory without re-uploading content - tags: - - contents - parameters: - - name: path - in: body - required: true - description: New path for file or directory. - schema: - type: object - properties: - path: - type: string - format: path - description: New path for file or directory - responses: - 200: - description: Path updated - headers: - Location: - description: Updated URL for the file or directory - type: string - format: url - schema: - $ref: '#/definitions/Contents' - 400: - description: No data provided - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - put: - summary: Save or upload file. - description: "Saves the file in the location specified by name and path. PUT is very similar to POST, but the requester specifies the name, whereas with POST, the server picks the name." - tags: - - contents - parameters: - - name: model - in: body - description: New path for file or directory - schema: - type: object - properties: - name: - type: string - description: The new filename if changed - path: - type: string - description: New path for file or directory - type: - type: string - description: Path dtype ('notebook', 'file', 'directory') - format: - type: string - description: File format ('json', 'text', 'base64') - content: - type: string - description: The actual body of the document excluding directory type - responses: - 200: - description: File saved - headers: - Location: - description: Updated URL for the file or directory - type: string - format: url - schema: - $ref: '#/definitions/Contents' - 201: - description: Path created - headers: - Location: - description: URL for the file or directory - type: string - format: url - schema: - $ref: '#/definitions/Contents' - 400: - description: No data provided - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - delete: - summary: Delete a file in the given path - tags: - - contents - responses: - 204: - description: File deleted - headers: - Location: - description: URL for the removed file - type: string - format: url - /api/contents/{path}/checkpoints: - parameters: - - $ref: '#/parameters/path' - get: - summary: Get a list of checkpoints for a file - description: List checkpoints for a given file. There will typically be zero or one results. - tags: - - contents - responses: - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - 200: - description: List of checkpoints for a file - schema: - type: array - items: - $ref: '#/definitions/Checkpoints' - 500: - description: Model key error - post: - summary: Create a new checkpoint for a file - description: "Create a new checkpoint with the current state of a file. With the default FileContentsManager, only one checkpoint is supported, so creating new checkpoints clobbers existing ones." - tags: - - contents - responses: - 201: - description: Checkpoint created - headers: - Location: - description: URL for the checkpoint - type: string - format: url - schema: - $ref: '#/definitions/Checkpoints' - 404: - description: No item found - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - /api/contents/{path}/checkpoints/{checkpoint_id}: - post: - summary: Restore a file to a particular checkpointed state - parameters: - - $ref: "#/parameters/path" - - $ref: "#/parameters/checkpoint_id" - tags: - - contents - responses: - 204: - description: Checkpoint restored - 400: - description: Bad request - schema: - type: object - properties: - error: - type: string - description: Error condition - reason: - type: string - description: Explanation of error reason - delete: - summary: Delete a checkpoint - parameters: - - $ref: "#/parameters/path" - - $ref: "#/parameters/checkpoint_id" - tags: - - contents - responses: - 204: - description: Checkpoint deleted - /api/sessions/{session}: - parameters: - - $ref: '#/parameters/session' - get: - summary: Get session - tags: - - sessions - responses: - 200: - description: Session - schema: - $ref: '#/definitions/Session' - patch: - summary: "This can be used to rename the session." - tags: - - sessions - parameters: - - name: model - in: body - required: true - schema: - $ref: '#/definitions/Session' - responses: - 200: - description: Session - schema: - $ref: '#/definitions/Session' - 400: - description: No data provided - delete: - summary: Delete a session - tags: - - sessions - responses: - 204: - description: Session (and kernel) were deleted - 410: - description: "Kernel was deleted before the session, and the session was *not* deleted (TODO - check to make sure session wasn't deleted)" - /api/sessions: - get: - summary: List available sessions - tags: - - sessions - responses: - 200: - description: List of current sessions - schema: - type: array - items: - $ref: '#/definitions/Session' - post: - summary: "Create a new session, or return an existing session if a session of the same name already exists" - tags: - - sessions - parameters: - - name: session - in: body - schema: - $ref: '#/definitions/Session' - responses: - 201: - description: Session created or returned - schema: - $ref: '#/definitions/Session' - headers: - Location: - description: URL for session commands - type: string - format: url - 501: - description: Session not available - schema: - type: object - description: error message - properties: - message: - type: string - short_message: - type: string - - /api/kernels: - get: - summary: List the JSON data for all kernels that are currently running - tags: - - kernels - responses: - 200: - description: List of currently-running kernel uuids - schema: - type: array - items: - $ref: '#/definitions/Kernel' - post: - summary: Start a kernel and return the uuid - tags: - - kernels - parameters: - - name: name - in: body - description: Kernel spec name (defaults to default kernel spec for server) - schema: - type: object - properties: - name: - type: string - responses: - 201: - description: Kernel started - schema: - $ref: '#/definitions/Kernel' - headers: - Location: - description: Model for started kernel - type: string - format: url - /api/kernels/{kernel_id}: - parameters: - - $ref: '#/parameters/kernel' - get: - summary: Get kernel information - tags: - - kernels - responses: - 200: - description: Kernel information - schema: - $ref: '#/definitions/Kernel' - delete: - summary: Kill a kernel and delete the kernel id - tags: - - kernels - responses: - 204: - description: Kernel deleted - /api/kernels/{kernel_id}/interrupt: - parameters: - - $ref: '#/parameters/kernel' - post: - summary: Interrupt a kernel - tags: - - kernels - responses: - 204: - description: Kernel interrupted - /api/kernels/{kernel_id}/restart: - parameters: - - $ref: '#/parameters/kernel' - post: - summary: Restart a kernel - tags: - - kernels - responses: - 200: - description: Kernel interrupted - headers: - Location: - description: URL for kernel commands - type: string - format: url - schema: - $ref: '#/definitions/Kernel' - - /api/kernelspecs: - get: - summary: Get kernel specs - tags: - - kernelspecs - responses: - 200: - description: Kernel specs - schema: - type: object - properties: - default: - type: string - description: Default kernel name - kernelspecs: - type: object - additionalProperties: - $ref: '#/definitions/KernelSpec' - /api/config/{section_name}: - get: - summary: Get a configuration section by name - parameters: - - $ref: "#/parameters/section_name" - tags: - - config - responses: - 200: - description: Configuration object - schema: - type: object - patch: - summary: Update a configuration section by name - tags: - - config - parameters: - - $ref: "#/parameters/section_name" - - name: configuration - in: body - schema: - type: object - responses: - 200: - description: Configuration object - schema: - type: object - - /api/terminals: - get: - summary: Get available terminals - tags: - - terminals - responses: - 200: - description: A list of all available terminal ids. - schema: - type: array - items: - $ref: '#/definitions/Terminal' - 403: - description: Forbidden to access - 404: - description: Not found - - post: - summary: Create a new terminal - tags: - - terminals - responses: - 200: - description: Succesfully created a new terminal - schema: - $ref: '#/definitions/Terminal' - 403: - description: Forbidden to access - 404: - description: Not found - - /api/terminals/{terminal_id}: - get: - summary: Get a terminal session corresponding to an id. - tags: - - terminals - parameters: - - $ref: '#/parameters/terminal_id' - responses: - 200: - description: Terminal session with given id - schema: - $ref: '#/definitions/Terminal' - 403: - description: Forbidden to access - 404: - description: Not found - - delete: - summary: Delete a terminal session corresponding to an id. - tags: - - terminals - parameters: - - $ref: '#/parameters/terminal_id' - responses: - 204: - description: Succesfully deleted terminal session - 403: - description: Forbidden to access - 404: - description: Not found - - - - - /api/status: - get: - summary: Get the current status/activity of the server. - tags: - - status - responses: - 200: - description: The current status of the server - schema: - $ref: '#/definitions/APIStatus' - - /api/spec.yaml: - get: - summary: Get the current spec for the notebook server's APIs. - tags: - - api-spec - produces: - - text/x-yaml - responses: - 200: - description: The current spec for the notebook server's APIs. - schema: - type: file -definitions: - APIStatus: - description: | - Notebook server API status. - Added in notebook 5.0. - properties: - started: - type: string - description: | - ISO8601 timestamp indicating when the notebook server started. - last_activity: - type: string - description: | - ISO8601 timestamp indicating the last activity on the server, - either on the REST API or kernel activity. - connections: - type: number - description: | - The total number of currently open connections to kernels. - kernels: - type: number - description: | - The total number of running kernels. - KernelSpec: - description: Kernel spec (contents of kernel.json) - properties: - name: - type: string - description: Unique name for kernel - KernelSpecFile: - $ref: '#/definitions/KernelSpecFile' - resources: - type: object - properties: - kernel.js: - type: string - format: filename - description: path for kernel.js file - kernel.css: - type: string - format: filename - description: path for kernel.css file - logo-*: - type: string - format: filename - description: path for logo file. Logo filenames are of the form `logo-widthxheight` - KernelSpecFile: - description: Kernel spec json file - required: - - argv - - display_name - - language - properties: - language: - type: string - description: The programming language which this kernel runs. This will be stored in notebook metadata. - argv: - type: array - description: "A list of command line arguments used to start the kernel. The text `{connection_file}` in any argument will be replaced with the path to the connection file." - items: - type: string - display_name: - type: string - description: "The kernel's name as it should be displayed in the UI. Unlike the kernel name used in the API, this can contain arbitrary unicode characters." - codemirror_mode: - type: string - description: Codemirror mode. Can be a string *or* an valid Codemirror mode object. This defaults to the string from the `language` property. - env: - type: object - description: A dictionary of environment variables to set for the kernel. These will be added to the current environment variables. - additionalProperties: - type: string - help_links: - type: array - description: Help items to be displayed in the help menu in the notebook UI. - items: - type: object - required: - - text - - url - properties: - text: - type: string - description: menu item link text - url: - type: string - format: URL - description: menu item link url - Kernel: - description: Kernel information - required: - - id - - name - properties: - id: - type: string - format: uuid - description: uuid of kernel - name: - type: string - description: kernel spec name - last_activity: - type: string - description: | - ISO 8601 timestamp for the last-seen activity on this kernel. - Use this in combination with execution_state == 'idle' to identify - which kernels have been idle since a given time. - Timestamps will be UTC, indicated 'Z' suffix. - Added in notebook server 5.0. - connections: - type: number - description: | - The number of active connections to this kernel. - execution_state: - type: string - description: | - Current execution state of the kernel (typically 'idle' or 'busy', but may be other values, such as 'starting'). - Added in notebook server 5.0. - Session: - description: A session - type: object - properties: - id: - type: string - format: uuid - path: - type: string - description: path to the session - name: - type: string - description: name of the session - type: - type: string - description: session type - kernel: - $ref: '#/definitions/Kernel' - Contents: - description: "A contents object. The content and format keys may be null if content is not contained. If type is 'file', then the mimetype will be null." - type: object - required: - - type - - name - - path - - writable - - created - - last_modified - - mimetype - - format - - content - properties: - name: - type: string - description: "Name of file or directory, equivalent to the last part of the path" - path: - type: string - description: Full path for file or directory - type: - type: string - description: Type of content - enum: - - directory - - file - - notebook - writable: - type: boolean - description: indicates whether the requester has permission to edit the file - created: - type: string - description: Creation timestamp - format: dateTime - last_modified: - type: string - description: Last modified timestamp - format: dateTime - size: - type: integer - description: "The size of the file or notebook in bytes. If no size is provided, defaults to null." - mimetype: - type: string - description: "The mimetype of a file. If content is not null, and type is 'file', this will contain the mimetype of the file, otherwise this will be null." - content: - type: string - description: "The content, if requested (otherwise null). Will be an array if type is 'directory'" - format: - type: string - description: Format of content (one of null, 'text', 'base64', 'json') - Checkpoints: - description: A checkpoint object. - type: object - required: - - id - - last_modified - properties: - id: - type: string - description: Unique id for the checkpoint. - last_modified: - type: string - description: Last modified timestamp - format: dateTime - Terminal: - description: A Terminal object - type: object - required: - - name - properties: - name: - type: string - description: name of terminal - last_activity: - type: string - description: | - ISO 8601 timestamp for the last-seen activity on this terminal. Use - this to identify which terminals have been inactive since a given time. - Timestamps will be UTC, indicated 'Z' suffix. diff --git a/notebook/services/api/handlers.py b/notebook/services/api/handlers.py deleted file mode 100644 index 23446e005..000000000 --- a/notebook/services/api/handlers.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Tornado handlers for api specifications.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import json -import os - -from tornado import gen, web - -from ...base.handlers import IPythonHandler, APIHandler -from notebook._tz import utcfromtimestamp, isoformat -from notebook.utils import maybe_future - - -class APISpecHandler(web.StaticFileHandler, IPythonHandler): - - def initialize(self): - web.StaticFileHandler.initialize(self, path=os.path.dirname(__file__)) - - @web.authenticated - def get(self): - self.log.warning("Serving api spec (experimental, incomplete)") - return web.StaticFileHandler.get(self, 'api.yaml') - - def get_content_type(self): - return 'text/x-yaml' - - -class APIStatusHandler(APIHandler): - - _track_activity = False - - @web.authenticated - @gen.coroutine - def get(self): - # if started was missing, use unix epoch - started = self.settings.get('started', utcfromtimestamp(0)) - started = isoformat(started) - - kernels = yield maybe_future(self.kernel_manager.list_kernels()) - total_connections = sum(k['connections'] for k in kernels) - last_activity = isoformat(self.application.last_activity()) - model = { - 'started': started, - 'last_activity': last_activity, - 'kernels': len(kernels), - 'connections': total_connections, - } - self.finish(json.dumps(model, sort_keys=True)) - - -default_handlers = [ - (r"/api/spec.yaml", APISpecHandler), - (r"/api/status", APIStatusHandler), -] diff --git a/notebook/services/api/tests/__init__.py b/notebook/services/api/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/api/tests/test_api.py b/notebook/services/api/tests/test_api.py deleted file mode 100644 index d09a06032..000000000 --- a/notebook/services/api/tests/test_api.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Test the basic /api endpoints""" - -from datetime import timedelta - -from notebook._tz import isoformat, utcnow -from notebook.utils import url_path_join -from notebook.tests.launchnotebook import NotebookTestBase - - -class APITest(NotebookTestBase): - """Test the kernels web service API""" - - def _req(self, verb, path, **kwargs): - r = self.request(verb, url_path_join('api', path)) - r.raise_for_status() - return r - - def get(self, path, **kwargs): - return self._req('GET', path) - - def test_get_spec(self): - r = self.get('spec.yaml') - assert r.text - - def test_get_status(self): - r = self.get('status') - data = r.json() - assert data['connections'] == 0 - assert data['kernels'] == 0 - assert data['last_activity'].endswith('Z') - assert data['started'].endswith('Z') - assert data['started'] == isoformat(self.notebook.web_app.settings['started']) - - def test_no_track_activity(self): - # initialize with old last api activity - old = utcnow() - timedelta(days=1) - settings = self.notebook.web_app.settings - settings['api_last_activity'] = old - # accessing status doesn't update activity - self.get('status') - assert settings['api_last_activity'] == old - # accessing with ?no_track_activity doesn't update activity - self.get('contents?no_track_activity=1') - assert settings['api_last_activity'] == old - # accessing without ?no_track_activity does update activity - self.get('contents') - assert settings['api_last_activity'] > old diff --git a/notebook/services/config/__init__.py b/notebook/services/config/__init__.py deleted file mode 100644 index d8d938020..000000000 --- a/notebook/services/config/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .manager import ConfigManager diff --git a/notebook/services/config/handlers.py b/notebook/services/config/handlers.py deleted file mode 100644 index aae648075..000000000 --- a/notebook/services/config/handlers.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Tornado handlers for frontend config storage.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. -import json -import os -import io -import errno -from tornado import web - -from ...base.handlers import APIHandler - -class ConfigHandler(APIHandler): - - @web.authenticated - def get(self, section_name): - self.set_header("Content-Type", 'application/json') - self.finish(json.dumps(self.config_manager.get(section_name))) - - @web.authenticated - def put(self, section_name): - data = self.get_json_body() # Will raise 400 if content is not valid JSON - self.config_manager.set(section_name, data) - self.set_status(204) - - @web.authenticated - def patch(self, section_name): - new_data = self.get_json_body() - section = self.config_manager.update(section_name, new_data) - self.finish(json.dumps(section)) - - -# URL to handler mappings - -section_name_regex = r"(?P\w+)" - -default_handlers = [ - (r"/api/config/%s" % section_name_regex, ConfigHandler), -] diff --git a/notebook/services/config/manager.py b/notebook/services/config/manager.py deleted file mode 100644 index 59f267dd9..000000000 --- a/notebook/services/config/manager.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Manager to read and modify frontend config data in JSON files. -""" -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import os.path - -from notebook.config_manager import BaseJSONConfigManager, recursive_update -from jupyter_core.paths import jupyter_config_dir, jupyter_config_path -from traitlets import Unicode, Instance, List, observe, default -from traitlets.config import LoggingConfigurable - - -class ConfigManager(LoggingConfigurable): - """Config Manager used for storing notebook frontend config""" - - # Public API - - def get(self, section_name): - """Get the config from all config sections.""" - config = {} - # step through back to front, to ensure front of the list is top priority - for p in self.read_config_path[::-1]: - cm = BaseJSONConfigManager(config_dir=p) - recursive_update(config, cm.get(section_name)) - return config - - def set(self, section_name, data): - """Set the config only to the user's config.""" - return self.write_config_manager.set(section_name, data) - - def update(self, section_name, new_data): - """Update the config only to the user's config.""" - return self.write_config_manager.update(section_name, new_data) - - # Private API - - read_config_path = List(Unicode()) - - @default('read_config_path') - def _default_read_config_path(self): - return [os.path.join(p, 'nbconfig') for p in jupyter_config_path()] - - write_config_dir = Unicode() - - @default('write_config_dir') - def _default_write_config_dir(self): - return os.path.join(jupyter_config_dir(), 'nbconfig') - - write_config_manager = Instance(BaseJSONConfigManager) - - @default('write_config_manager') - def _default_write_config_manager(self): - return BaseJSONConfigManager(config_dir=self.write_config_dir) - - @observe('write_config_dir') - def _update_write_config_dir(self, change): - self.write_config_manager = BaseJSONConfigManager(config_dir=self.write_config_dir) diff --git a/notebook/services/config/tests/__init__.py b/notebook/services/config/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/config/tests/test_config_api.py b/notebook/services/config/tests/test_config_api.py deleted file mode 100644 index a4df8f40f..000000000 --- a/notebook/services/config/tests/test_config_api.py +++ /dev/null @@ -1,67 +0,0 @@ -"""Test the config webservice API.""" - -import json - -import requests - -from notebook.utils import url_path_join -from notebook.tests.launchnotebook import NotebookTestBase - - -class ConfigAPI(object): - """Wrapper for notebook API calls.""" - def __init__(self, request): - self.request = request - - def _req(self, verb, section, body=None): - response = self.request(verb, - url_path_join('api/config', section), - data=body, - ) - response.raise_for_status() - return response - - def get(self, section): - return self._req('GET', section) - - def set(self, section, values): - return self._req('PUT', section, json.dumps(values)) - - def modify(self, section, values): - return self._req('PATCH', section, json.dumps(values)) - -class APITest(NotebookTestBase): - """Test the config web service API""" - def setUp(self): - self.config_api = ConfigAPI(self.request) - - def test_create_retrieve_config(self): - sample = {'foo': 'bar', 'baz': 73} - r = self.config_api.set('example', sample) - self.assertEqual(r.status_code, 204) - - r = self.config_api.get('example') - self.assertEqual(r.status_code, 200) - self.assertEqual(r.json(), sample) - - def test_modify(self): - sample = {'foo': 'bar', 'baz': 73, - 'sub': {'a': 6, 'b': 7}, 'sub2': {'c': 8}} - self.config_api.set('example', sample) - - r = self.config_api.modify('example', {'foo': None, # should delete foo - 'baz': 75, - 'wib': [1,2,3], - 'sub': {'a': 8, 'b': None, 'd': 9}, - 'sub2': {'c': None} # should delete sub2 - }) - self.assertEqual(r.status_code, 200) - self.assertEqual(r.json(), {'baz': 75, 'wib': [1,2,3], - 'sub': {'a': 8, 'd': 9}}) - - def test_get_unknown(self): - # We should get an empty config dictionary instead of a 404 - r = self.config_api.get('nonexistant') - self.assertEqual(r.status_code, 200) - self.assertEqual(r.json(), {}) - diff --git a/notebook/services/contents/__init__.py b/notebook/services/contents/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/contents/checkpoints.py b/notebook/services/contents/checkpoints.py deleted file mode 100644 index c29a669c2..000000000 --- a/notebook/services/contents/checkpoints.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -Classes for managing Checkpoints. -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from tornado.web import HTTPError - -from traitlets.config.configurable import LoggingConfigurable - - -class Checkpoints(LoggingConfigurable): - """ - Base class for managing checkpoints for a ContentsManager. - - Subclasses are required to implement: - - create_checkpoint(self, contents_mgr, path) - restore_checkpoint(self, contents_mgr, checkpoint_id, path) - rename_checkpoint(self, checkpoint_id, old_path, new_path) - delete_checkpoint(self, checkpoint_id, path) - list_checkpoints(self, path) - """ - def create_checkpoint(self, contents_mgr, path): - """Create a checkpoint.""" - raise NotImplementedError("must be implemented in a subclass") - - def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint""" - raise NotImplementedError("must be implemented in a subclass") - - def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """Rename a single checkpoint from old_path to new_path.""" - raise NotImplementedError("must be implemented in a subclass") - - def delete_checkpoint(self, checkpoint_id, path): - """delete a checkpoint for a file""" - raise NotImplementedError("must be implemented in a subclass") - - def list_checkpoints(self, path): - """Return a list of checkpoints for a given file""" - raise NotImplementedError("must be implemented in a subclass") - - def rename_all_checkpoints(self, old_path, new_path): - """Rename all checkpoints for old_path to new_path.""" - for cp in self.list_checkpoints(old_path): - self.rename_checkpoint(cp['id'], old_path, new_path) - - def delete_all_checkpoints(self, path): - """Delete all checkpoints for the given path.""" - for checkpoint in self.list_checkpoints(path): - self.delete_checkpoint(checkpoint['id'], path) - - -class GenericCheckpointsMixin(object): - """ - Helper for creating Checkpoints subclasses that can be used with any - ContentsManager. - - Provides a ContentsManager-agnostic implementation of `create_checkpoint` - and `restore_checkpoint` in terms of the following operations: - - - create_file_checkpoint(self, content, format, path) - - create_notebook_checkpoint(self, nb, path) - - get_file_checkpoint(self, checkpoint_id, path) - - get_notebook_checkpoint(self, checkpoint_id, path) - - To create a generic CheckpointManager, add this mixin to a class that - implement the above four methods plus the remaining Checkpoints API - methods: - - - delete_checkpoint(self, checkpoint_id, path) - - list_checkpoints(self, path) - - rename_checkpoint(self, checkpoint_id, old_path, new_path) - """ - - def create_checkpoint(self, contents_mgr, path): - model = contents_mgr.get(path, content=True) - type = model['type'] - if type == 'notebook': - return self.create_notebook_checkpoint( - model['content'], - path, - ) - elif type == 'file': - return self.create_file_checkpoint( - model['content'], - model['format'], - path, - ) - else: - raise HTTPError(500, u'Unexpected type %s' % type) - - def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint.""" - type = contents_mgr.get(path, content=False)['type'] - if type == 'notebook': - model = self.get_notebook_checkpoint(checkpoint_id, path) - elif type == 'file': - model = self.get_file_checkpoint(checkpoint_id, path) - else: - raise HTTPError(500, u'Unexpected type %s' % type) - contents_mgr.save(model, path) - - # Required Methods - def create_file_checkpoint(self, content, format, path): - """Create a checkpoint of the current state of a file - - Returns a checkpoint model for the new checkpoint. - """ - raise NotImplementedError("must be implemented in a subclass") - - def create_notebook_checkpoint(self, nb, path): - """Create a checkpoint of the current state of a file - - Returns a checkpoint model for the new checkpoint. - """ - raise NotImplementedError("must be implemented in a subclass") - - def get_file_checkpoint(self, checkpoint_id, path): - """Get the content of a checkpoint for a non-notebook file. - - Returns a dict of the form: - { - 'type': 'file', - 'content': , - 'format': {'text','base64'}, - } - """ - raise NotImplementedError("must be implemented in a subclass") - - def get_notebook_checkpoint(self, checkpoint_id, path): - """Get the content of a checkpoint for a notebook. - - Returns a dict of the form: - { - 'type': 'notebook', - 'content': , - } - """ - raise NotImplementedError("must be implemented in a subclass") diff --git a/notebook/services/contents/filecheckpoints.py b/notebook/services/contents/filecheckpoints.py deleted file mode 100644 index 5a9c83574..000000000 --- a/notebook/services/contents/filecheckpoints.py +++ /dev/null @@ -1,202 +0,0 @@ -""" -File-based Checkpoints implementations. -""" -import os -import shutil - -from tornado.web import HTTPError - -from .checkpoints import ( - Checkpoints, - GenericCheckpointsMixin, -) -from .fileio import FileManagerMixin - -from jupyter_core.utils import ensure_dir_exists -from ipython_genutils.py3compat import getcwd -from traitlets import Unicode - -from notebook import _tz as tz - - -class FileCheckpoints(FileManagerMixin, Checkpoints): - """ - A Checkpoints that caches checkpoints for files in adjacent - directories. - - Only works with FileContentsManager. Use GenericFileCheckpoints if - you want file-based checkpoints with another ContentsManager. - """ - - checkpoint_dir = Unicode( - '.ipynb_checkpoints', - config=True, - help="""The directory name in which to keep file checkpoints - - This is a path relative to the file's own directory. - - By default, it is .ipynb_checkpoints - """, - ) - - root_dir = Unicode(config=True) - - def _root_dir_default(self): - try: - return self.parent.root_dir - except AttributeError: - return getcwd() - - # ContentsManager-dependent checkpoint API - def create_checkpoint(self, contents_mgr, path): - """Create a checkpoint.""" - checkpoint_id = u'checkpoint' - src_path = contents_mgr._get_os_path(path) - dest_path = self.checkpoint_path(checkpoint_id, path) - self._copy(src_path, dest_path) - return self.checkpoint_model(checkpoint_id, dest_path) - - def restore_checkpoint(self, contents_mgr, checkpoint_id, path): - """Restore a checkpoint.""" - src_path = self.checkpoint_path(checkpoint_id, path) - dest_path = contents_mgr._get_os_path(path) - self._copy(src_path, dest_path) - - # ContentsManager-independent checkpoint API - def rename_checkpoint(self, checkpoint_id, old_path, new_path): - """Rename a checkpoint from old_path to new_path.""" - old_cp_path = self.checkpoint_path(checkpoint_id, old_path) - new_cp_path = self.checkpoint_path(checkpoint_id, new_path) - if os.path.isfile(old_cp_path): - self.log.debug( - "Renaming checkpoint %s -> %s", - old_cp_path, - new_cp_path, - ) - with self.perm_to_403(): - shutil.move(old_cp_path, new_cp_path) - - def delete_checkpoint(self, checkpoint_id, path): - """delete a file's checkpoint""" - path = path.strip('/') - cp_path = self.checkpoint_path(checkpoint_id, path) - if not os.path.isfile(cp_path): - self.no_such_checkpoint(path, checkpoint_id) - - self.log.debug("unlinking %s", cp_path) - with self.perm_to_403(): - os.unlink(cp_path) - - def list_checkpoints(self, path): - """list the checkpoints for a given file - - This contents manager currently only supports one checkpoint per file. - """ - path = path.strip('/') - checkpoint_id = "checkpoint" - os_path = self.checkpoint_path(checkpoint_id, path) - if not os.path.isfile(os_path): - return [] - else: - return [self.checkpoint_model(checkpoint_id, os_path)] - - # Checkpoint-related utilities - def checkpoint_path(self, checkpoint_id, path): - """find the path to a checkpoint""" - path = path.strip('/') - parent, name = ('/' + path).rsplit('/', 1) - parent = parent.strip('/') - basename, ext = os.path.splitext(name) - filename = u"{name}-{checkpoint_id}{ext}".format( - name=basename, - checkpoint_id=checkpoint_id, - ext=ext, - ) - os_path = self._get_os_path(path=parent) - cp_dir = os.path.join(os_path, self.checkpoint_dir) - with self.perm_to_403(): - ensure_dir_exists(cp_dir) - cp_path = os.path.join(cp_dir, filename) - return cp_path - - def checkpoint_model(self, checkpoint_id, os_path): - """construct the info dict for a given checkpoint""" - stats = os.stat(os_path) - last_modified = tz.utcfromtimestamp(stats.st_mtime) - info = dict( - id=checkpoint_id, - last_modified=last_modified, - ) - return info - - # Error Handling - def no_such_checkpoint(self, path, checkpoint_id): - raise HTTPError( - 404, - u'Checkpoint does not exist: %s@%s' % (path, checkpoint_id) - ) - - -class GenericFileCheckpoints(GenericCheckpointsMixin, FileCheckpoints): - """ - Local filesystem Checkpoints that works with any conforming - ContentsManager. - """ - def create_file_checkpoint(self, content, format, path): - """Create a checkpoint from the current content of a file.""" - path = path.strip('/') - # only the one checkpoint ID: - checkpoint_id = u"checkpoint" - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - self.log.debug("creating checkpoint for %s", path) - with self.perm_to_403(): - self._save_file(os_checkpoint_path, content, format=format) - - # return the checkpoint info - return self.checkpoint_model(checkpoint_id, os_checkpoint_path) - - def create_notebook_checkpoint(self, nb, path): - """Create a checkpoint from the current content of a notebook.""" - path = path.strip('/') - # only the one checkpoint ID: - checkpoint_id = u"checkpoint" - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - self.log.debug("creating checkpoint for %s", path) - with self.perm_to_403(): - self._save_notebook(os_checkpoint_path, nb) - - # return the checkpoint info - return self.checkpoint_model(checkpoint_id, os_checkpoint_path) - - def get_notebook_checkpoint(self, checkpoint_id, path): - """Get a checkpoint for a notebook.""" - path = path.strip('/') - self.log.info("restoring %s from checkpoint %s", path, checkpoint_id) - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - - if not os.path.isfile(os_checkpoint_path): - self.no_such_checkpoint(path, checkpoint_id) - - return { - 'type': 'notebook', - 'content': self._read_notebook( - os_checkpoint_path, - as_version=4, - ), - } - - def get_file_checkpoint(self, checkpoint_id, path): - """Get a checkpoint for a file.""" - path = path.strip('/') - self.log.info("restoring %s from checkpoint %s", path, checkpoint_id) - os_checkpoint_path = self.checkpoint_path(checkpoint_id, path) - - if not os.path.isfile(os_checkpoint_path): - self.no_such_checkpoint(path, checkpoint_id) - - content, format = self._read_file(os_checkpoint_path, format=None) - return { - 'type': 'file', - 'content': content, - 'format': format, - } diff --git a/notebook/services/contents/fileio.py b/notebook/services/contents/fileio.py deleted file mode 100644 index f99504e32..000000000 --- a/notebook/services/contents/fileio.py +++ /dev/null @@ -1,341 +0,0 @@ -""" -Utilities for file-based Contents/Checkpoints managers. -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from contextlib import contextmanager -import errno -import io -import os -import shutil - -from tornado.web import HTTPError - -from notebook.utils import ( - to_api_path, - to_os_path, -) -import nbformat - -from ipython_genutils.py3compat import str_to_unicode - -from traitlets.config import Configurable -from traitlets import Bool - -from base64 import encodebytes, decodebytes - - -def replace_file(src, dst): - """ replace dst with src - - switches between os.replace or os.rename based on python 2.7 or python 3 - """ - if hasattr(os, 'replace'): # PY3 - os.replace(src, dst) - else: - if os.name == 'nt' and os.path.exists(dst): - # Rename over existing file doesn't work on Windows - os.remove(dst) - os.rename(src, dst) - -def copy2_safe(src, dst, log=None): - """copy src to dst - - like shutil.copy2, but log errors in copystat instead of raising - """ - shutil.copyfile(src, dst) - try: - shutil.copystat(src, dst) - except OSError: - if log: - log.debug("copystat on %s failed", dst, exc_info=True) - -def path_to_intermediate(path): - '''Name of the intermediate file used in atomic writes. - - The .~ prefix will make Dropbox ignore the temporary file.''' - dirname, basename = os.path.split(path) - return os.path.join(dirname, '.~'+basename) - -def path_to_invalid(path): - '''Name of invalid file after a failed atomic write and subsequent read.''' - dirname, basename = os.path.split(path) - return os.path.join(dirname, basename+'.invalid') - -@contextmanager -def atomic_writing(path, text=True, encoding='utf-8', log=None, **kwargs): - """Context manager to write to a file only if the entire write is successful. - - This works by copying the previous file contents to a temporary file in the - same directory, and renaming that file back to the target if the context - exits with an error. If the context is successful, the new data is synced to - disk and the temporary file is removed. - - Parameters - ---------- - path : str - The target file to write to. - - text : bool, optional - Whether to open the file in text mode (i.e. to write unicode). Default is - True. - - encoding : str, optional - The encoding to use for files opened in text mode. Default is UTF-8. - - **kwargs - Passed to :func:`io.open`. - """ - # realpath doesn't work on Windows: https://bugs.python.org/issue9949 - # Luckily, we only need to resolve the file itself being a symlink, not - # any of its directories, so this will suffice: - if os.path.islink(path): - path = os.path.join(os.path.dirname(path), os.readlink(path)) - - tmp_path = path_to_intermediate(path) - - if os.path.isfile(path): - copy2_safe(path, tmp_path, log=log) - - if text: - # Make sure that text files have Unix linefeeds by default - kwargs.setdefault('newline', '\n') - fileobj = io.open(path, 'w', encoding=encoding, **kwargs) - else: - fileobj = io.open(path, 'wb', **kwargs) - - try: - yield fileobj - except: - # Failed! Move the backup file back to the real path to avoid corruption - fileobj.close() - replace_file(tmp_path, path) - raise - - # Flush to disk - fileobj.flush() - os.fsync(fileobj.fileno()) - fileobj.close() - - # Written successfully, now remove the backup copy - if os.path.isfile(tmp_path): - os.remove(tmp_path) - - - -@contextmanager -def _simple_writing(path, text=True, encoding='utf-8', log=None, **kwargs): - """Context manager to write file without doing atomic writing - ( for weird filesystem eg: nfs). - - Parameters - ---------- - path : str - The target file to write to. - - text : bool, optional - Whether to open the file in text mode (i.e. to write unicode). Default is - True. - - encoding : str, optional - The encoding to use for files opened in text mode. Default is UTF-8. - - **kwargs - Passed to :func:`io.open`. - """ - # realpath doesn't work on Windows: https://bugs.python.org/issue9949 - # Luckily, we only need to resolve the file itself being a symlink, not - # any of its directories, so this will suffice: - if os.path.islink(path): - path = os.path.join(os.path.dirname(path), os.readlink(path)) - - if text: - # Make sure that text files have Unix linefeeds by default - kwargs.setdefault('newline', '\n') - fileobj = io.open(path, 'w', encoding=encoding, **kwargs) - else: - fileobj = io.open(path, 'wb', **kwargs) - - try: - yield fileobj - except: - fileobj.close() - raise - - fileobj.close() - - - - -class FileManagerMixin(Configurable): - """ - Mixin for ContentsAPI classes that interact with the filesystem. - - Provides facilities for reading, writing, and copying both notebooks and - generic files. - - Shared by FileContentsManager and FileCheckpoints. - - Note - ---- - Classes using this mixin must provide the following attributes: - - root_dir : unicode - A directory against which API-style paths are to be resolved. - - log : logging.Logger - """ - - use_atomic_writing = Bool(True, config=True, help= - """By default notebooks are saved on disk on a temporary file and then if successfully written, it replaces the old ones. - This procedure, namely 'atomic_writing', causes some bugs on file system without operation order enforcement (like some networked fs). - If set to False, the new notebook is written directly on the old one which could fail (eg: full filesystem or quota )""") - - @contextmanager - def open(self, os_path, *args, **kwargs): - """wrapper around io.open that turns permission errors into 403""" - with self.perm_to_403(os_path): - with io.open(os_path, *args, **kwargs) as f: - yield f - - @contextmanager - def atomic_writing(self, os_path, *args, **kwargs): - """wrapper around atomic_writing that turns permission errors to 403. - Depending on flag 'use_atomic_writing', the wrapper perform an actual atomic writing or - simply writes the file (whatever an old exists or not)""" - with self.perm_to_403(os_path): - if self.use_atomic_writing: - with atomic_writing(os_path, *args, log=self.log, **kwargs) as f: - yield f - else: - with _simple_writing(os_path, *args, log=self.log, **kwargs) as f: - yield f - - @contextmanager - def perm_to_403(self, os_path=''): - """context manager for turning permission errors into 403.""" - try: - yield - except (OSError, IOError) as e: - if e.errno in {errno.EPERM, errno.EACCES}: - # make 403 error message without root prefix - # this may not work perfectly on unicode paths on Python 2, - # but nobody should be doing that anyway. - if not os_path: - os_path = str_to_unicode(e.filename or 'unknown file') - path = to_api_path(os_path, root=self.root_dir) - raise HTTPError(403, u'Permission denied: %s' % path) from e - else: - raise - - def _copy(self, src, dest): - """copy src to dest - - like shutil.copy2, but log errors in copystat - """ - copy2_safe(src, dest, log=self.log) - - def _get_os_path(self, path): - """Given an API path, return its file system path. - - Parameters - ---------- - path : string - The relative API path to the named file. - - Returns - ------- - path : string - Native, absolute OS path to for a file. - - Raises - ------ - 404: if path is outside root - """ - root = os.path.abspath(self.root_dir) - os_path = to_os_path(path, root) - if not (os.path.abspath(os_path) + os.path.sep).startswith(root): - raise HTTPError(404, "%s is outside root contents directory" % path) - return os_path - - def _read_notebook(self, os_path, as_version=4): - """Read a notebook from an os path.""" - with self.open(os_path, 'r', encoding='utf-8') as f: - try: - return nbformat.read(f, as_version=as_version) - except Exception as e: - e_orig = e - - # If use_atomic_writing is enabled, we'll guess that it was also - # enabled when this notebook was written and look for a valid - # atomic intermediate. - tmp_path = path_to_intermediate(os_path) - - if not self.use_atomic_writing or not os.path.exists(tmp_path): - raise HTTPError( - 400, - u"Unreadable Notebook: %s %r" % (os_path, e_orig), - ) - - # Move the bad file aside, restore the intermediate, and try again. - invalid_file = path_to_invalid(os_path) - replace_file(os_path, invalid_file) - replace_file(tmp_path, os_path) - return self._read_notebook(os_path, as_version) - - def _save_notebook(self, os_path, nb): - """Save a notebook to an os_path.""" - with self.atomic_writing(os_path, encoding='utf-8') as f: - nbformat.write(nb, f, version=nbformat.NO_CONVERT) - - def _read_file(self, os_path, format): - """Read a non-notebook file. - - os_path: The path to be read. - format: - If 'text', the contents will be decoded as UTF-8. - If 'base64', the raw bytes contents will be encoded as base64. - If not specified, try to decode as UTF-8, and fall back to base64 - """ - if not os.path.isfile(os_path): - raise HTTPError(400, "Cannot read non-file %s" % os_path) - - with self.open(os_path, 'rb') as f: - bcontent = f.read() - - if format is None or format == 'text': - # Try to interpret as unicode if format is unknown or if unicode - # was explicitly requested. - try: - return bcontent.decode('utf8'), 'text' - except UnicodeError as e: - if format == 'text': - raise HTTPError( - 400, - "%s is not UTF-8 encoded" % os_path, - reason='bad format', - ) from e - return encodebytes(bcontent).decode('ascii'), 'base64' - - def _save_file(self, os_path, content, format): - """Save content of a generic file.""" - if format not in {'text', 'base64'}: - raise HTTPError( - 400, - "Must specify format of file contents as 'text' or 'base64'", - ) - try: - if format == 'text': - bcontent = content.encode('utf8') - else: - b64_bytes = content.encode('ascii') - bcontent = decodebytes(b64_bytes) - except Exception as e: - raise HTTPError( - 400, u'Encoding error saving %s: %s' % (os_path, e) - ) from e - - with self.atomic_writing(os_path, text=False) as f: - f.write(bcontent) diff --git a/notebook/services/contents/filemanager.py b/notebook/services/contents/filemanager.py deleted file mode 100644 index 0c9386b2f..000000000 --- a/notebook/services/contents/filemanager.py +++ /dev/null @@ -1,609 +0,0 @@ -"""A contents manager that uses the local file system for storage.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from datetime import datetime -import errno -import io -import os -import shutil -import stat -import sys -import warnings -import mimetypes -import nbformat - -from send2trash import send2trash -from send2trash.exceptions import TrashPermissionError -from tornado import web - -from .filecheckpoints import FileCheckpoints -from .fileio import FileManagerMixin -from .manager import ContentsManager -from ...utils import exists - -from ipython_genutils.importstring import import_item -from traitlets import Any, Unicode, Bool, TraitError, observe, default, validate -from ipython_genutils.py3compat import getcwd, string_types - -from notebook import _tz as tz -from notebook.utils import ( - is_hidden, is_file_hidden, - to_api_path, -) -from notebook.base.handlers import AuthenticatedFileHandler -from notebook.transutils import _ - -from os.path import samefile - -_script_exporter = None - - -def _post_save_script(model, os_path, contents_manager, **kwargs): - """convert notebooks to Python script after save with nbconvert - - replaces `jupyter notebook --script` - """ - from nbconvert.exporters.script import ScriptExporter - warnings.warn("`_post_save_script` is deprecated and will be removed in Notebook 5.0", DeprecationWarning) - - if model['type'] != 'notebook': - return - - global _script_exporter - if _script_exporter is None: - _script_exporter = ScriptExporter(parent=contents_manager) - log = contents_manager.log - - base, ext = os.path.splitext(os_path) - script, resources = _script_exporter.from_filename(os_path) - script_fname = base + resources.get('output_extension', '.txt') - log.info("Saving script /%s", to_api_path(script_fname, contents_manager.root_dir)) - with io.open(script_fname, 'w', encoding='utf-8') as f: - f.write(script) - - -class FileContentsManager(FileManagerMixin, ContentsManager): - - root_dir = Unicode(config=True) - - @default('root_dir') - def _default_root_dir(self): - try: - return self.parent.notebook_dir - except AttributeError: - return getcwd() - - save_script = Bool(False, config=True, help='DEPRECATED, use post_save_hook. Will be removed in Notebook 5.0') - @observe('save_script') - def _update_save_script(self, change): - if not change['new']: - return - self.log.warning(""" - `--script` is deprecated and will be removed in notebook 5.0. - - You can trigger nbconvert via pre- or post-save hooks: - - ContentsManager.pre_save_hook - FileContentsManager.post_save_hook - - A post-save hook has been registered that calls: - - jupyter nbconvert --to script [notebook] - - which behaves similarly to `--script`. - """) - - self.post_save_hook = _post_save_script - - post_save_hook = Any(None, config=True, allow_none=True, - help="""Python callable or importstring thereof - - to be called on the path of a file just saved. - - This can be used to process the file on disk, - such as converting the notebook to a script or HTML via nbconvert. - - It will be called as (all arguments passed by keyword):: - - hook(os_path=os_path, model=model, contents_manager=instance) - - - path: the filesystem path to the file just written - - model: the model representing the file - - contents_manager: this ContentsManager instance - """ - ) - - @validate('post_save_hook') - def _validate_post_save_hook(self, proposal): - value = proposal['value'] - if isinstance(value, string_types): - value = import_item(value) - if not callable(value): - raise TraitError("post_save_hook must be callable") - return value - - def run_post_save_hook(self, model, os_path): - """Run the post-save hook if defined, and log errors""" - if self.post_save_hook: - try: - self.log.debug("Running post-save hook on %s", os_path) - self.post_save_hook(os_path=os_path, model=model, contents_manager=self) - except Exception as e: - self.log.error("Post-save hook failed o-n %s", os_path, exc_info=True) - raise web.HTTPError(500, u'Unexpected error while running post hook save: %s' - % e) from e - - @validate('root_dir') - def _validate_root_dir(self, proposal): - """Do a bit of validation of the root_dir.""" - value = proposal['value'] - if not os.path.isabs(value): - # If we receive a non-absolute path, make it absolute. - value = os.path.abspath(value) - if not os.path.isdir(value): - raise TraitError("%r is not a directory" % value) - return value - - @default('checkpoints_class') - def _checkpoints_class_default(self): - return FileCheckpoints - - delete_to_trash = Bool(True, config=True, - help="""If True (default), deleting files will send them to the - platform's trash/recycle bin, where they can be recovered. If False, - deleting files really deletes them.""") - - @default('files_handler_class') - def _files_handler_class_default(self): - return AuthenticatedFileHandler - - @default('files_handler_params') - def _files_handler_params_default(self): - return {'path': self.root_dir} - - def is_hidden(self, path): - """Does the API style path correspond to a hidden directory or file? - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root_dir). - - Returns - ------- - hidden : bool - Whether the path exists and is hidden. - """ - path = path.strip('/') - os_path = self._get_os_path(path=path) - return is_hidden(os_path, self.root_dir) - - def file_exists(self, path): - """Returns True if the file exists, else returns False. - - API-style wrapper for os.path.isfile - - Parameters - ---------- - path : string - The relative path to the file (with '/' as separator) - - Returns - ------- - exists : bool - Whether the file exists. - """ - path = path.strip('/') - os_path = self._get_os_path(path) - return os.path.isfile(os_path) - - def dir_exists(self, path): - """Does the API-style path refer to an extant directory? - - API-style wrapper for os.path.isdir - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root_dir). - - Returns - ------- - exists : bool - Whether the path is indeed a directory. - """ - path = path.strip('/') - os_path = self._get_os_path(path=path) - return os.path.isdir(os_path) - - def exists(self, path): - """Returns True if the path exists, else returns False. - - API-style wrapper for os.path.exists - - Parameters - ---------- - path : string - The API path to the file (with '/' as separator) - - Returns - ------- - exists : bool - Whether the target exists. - """ - path = path.strip('/') - os_path = self._get_os_path(path=path) - return exists(os_path) - - def _base_model(self, path): - """Build the common base of a contents model""" - os_path = self._get_os_path(path) - info = os.lstat(os_path) - - try: - # size of file - size = info.st_size - except (ValueError, OSError): - self.log.warning('Unable to get size.') - size = None - - try: - last_modified = tz.utcfromtimestamp(info.st_mtime) - except (ValueError, OSError): - # Files can rarely have an invalid timestamp - # https://github.com/jupyter/notebook/issues/2539 - # https://github.com/jupyter/notebook/issues/2757 - # Use the Unix epoch as a fallback so we don't crash. - self.log.warning('Invalid mtime %s for %s', info.st_mtime, os_path) - last_modified = datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC) - - try: - created = tz.utcfromtimestamp(info.st_ctime) - except (ValueError, OSError): # See above - self.log.warning('Invalid ctime %s for %s', info.st_ctime, os_path) - created = datetime(1970, 1, 1, 0, 0, tzinfo=tz.UTC) - - # Create the base model. - model = {} - model['name'] = path.rsplit('/', 1)[-1] - model['path'] = path - model['last_modified'] = last_modified - model['created'] = created - model['content'] = None - model['format'] = None - model['mimetype'] = None - model['size'] = size - - try: - model['writable'] = os.access(os_path, os.W_OK) - except OSError: - self.log.error("Failed to check write permissions on %s", os_path) - model['writable'] = False - return model - - def _dir_model(self, path, content=True): - """Build a model for a directory - - if content is requested, will include a listing of the directory - """ - os_path = self._get_os_path(path) - - four_o_four = u'directory does not exist: %r' % path - - if not os.path.isdir(os_path): - raise web.HTTPError(404, four_o_four) - elif is_hidden(os_path, self.root_dir) and not self.allow_hidden: - self.log.info("Refusing to serve hidden directory %r, via 404 Error", - os_path - ) - raise web.HTTPError(404, four_o_four) - - model = self._base_model(path) - model['type'] = 'directory' - model['size'] = None - if content: - model['content'] = contents = [] - os_dir = self._get_os_path(path) - for name in os.listdir(os_dir): - try: - os_path = os.path.join(os_dir, name) - except UnicodeDecodeError as e: - self.log.warning( - "failed to decode filename '%s': %s", name, e) - continue - - try: - st = os.lstat(os_path) - except OSError as e: - # skip over broken symlinks in listing - if e.errno == errno.ENOENT: - self.log.warning("%s doesn't exist", os_path) - else: - self.log.warning("Error stat-ing %s: %s", os_path, e) - continue - - if (not stat.S_ISLNK(st.st_mode) - and not stat.S_ISREG(st.st_mode) - and not stat.S_ISDIR(st.st_mode)): - self.log.debug("%s not a regular file", os_path) - continue - - try: - if self.should_list(name): - if self.allow_hidden or not is_file_hidden(os_path, stat_res=st): - contents.append( - self.get(path='%s/%s' % (path, name), content=False) - ) - except OSError as e: - # ELOOP: recursive symlink - if e.errno != errno.ELOOP: - self.log.warning( - "Unknown error checking if file %r is hidden", - os_path, - exc_info=True, - ) - model['format'] = 'json' - - return model - - - def _file_model(self, path, content=True, format=None): - """Build a model for a file - - if content is requested, include the file contents. - - format: - If 'text', the contents will be decoded as UTF-8. - If 'base64', the raw bytes contents will be encoded as base64. - If not specified, try to decode as UTF-8, and fall back to base64 - """ - model = self._base_model(path) - model['type'] = 'file' - - os_path = self._get_os_path(path) - model['mimetype'] = mimetypes.guess_type(os_path)[0] - - if content: - content, format = self._read_file(os_path, format) - if model['mimetype'] is None: - default_mime = { - 'text': 'text/plain', - 'base64': 'application/octet-stream' - }[format] - model['mimetype'] = default_mime - - model.update( - content=content, - format=format, - ) - - return model - - def _notebook_model(self, path, content=True): - """Build a notebook model - - if content is requested, the notebook content will be populated - as a JSON structure (not double-serialized) - """ - model = self._base_model(path) - model['type'] = 'notebook' - os_path = self._get_os_path(path) - - if content: - nb = self._read_notebook(os_path, as_version=4) - self.mark_trusted_cells(nb, path) - model['content'] = nb - model['format'] = 'json' - self.validate_notebook_model(model) - - return model - - def get(self, path, content=True, type=None, format=None): - """ Takes a path for an entity and returns its model - - Parameters - ---------- - path : str - the API path that describes the relative path for the target - content : bool - Whether to include the contents in the reply - type : str, optional - The requested type - 'file', 'notebook', or 'directory'. - Will raise HTTPError 400 if the content doesn't match. - format : str, optional - The requested format for file contents. 'text' or 'base64'. - Ignored if this returns a notebook or directory model. - - Returns - ------- - model : dict - the contents model. If content=True, returns the contents - of the file or directory as well. - """ - path = path.strip('/') - - if not self.exists(path): - raise web.HTTPError(404, u'No such file or directory: %s' % path) - - os_path = self._get_os_path(path) - if os.path.isdir(os_path): - if type not in (None, 'directory'): - raise web.HTTPError(400, - u'%s is a directory, not a %s' % (path, type), reason='bad type') - model = self._dir_model(path, content=content) - elif type == 'notebook' or (type is None and path.endswith('.ipynb')): - model = self._notebook_model(path, content=content) - else: - if type == 'directory': - raise web.HTTPError(400, - u'%s is not a directory' % path, reason='bad type') - model = self._file_model(path, content=content, format=format) - return model - - def _save_directory(self, os_path, model, path=''): - """create a directory""" - if is_hidden(os_path, self.root_dir) and not self.allow_hidden: - raise web.HTTPError(400, u'Cannot create hidden directory %r' % os_path) - if not os.path.exists(os_path): - with self.perm_to_403(): - os.mkdir(os_path) - elif not os.path.isdir(os_path): - raise web.HTTPError(400, u'Not a directory: %s' % (os_path)) - else: - self.log.debug("Directory %r already exists", os_path) - - def save(self, model, path=''): - """Save the file model and return the model with no content.""" - path = path.strip('/') - - if 'type' not in model: - raise web.HTTPError(400, u'No file type provided') - if 'content' not in model and model['type'] != 'directory': - raise web.HTTPError(400, u'No file content provided') - - os_path = self._get_os_path(path) - self.log.debug("Saving %s", os_path) - - self.run_pre_save_hook(model=model, path=path) - - try: - if model['type'] == 'notebook': - nb = nbformat.from_dict(model['content']) - self.check_and_sign(nb, path) - self._save_notebook(os_path, nb) - # One checkpoint should always exist for notebooks. - if not self.checkpoints.list_checkpoints(path): - self.create_checkpoint(path) - elif model['type'] == 'file': - # Missing format will be handled internally by _save_file. - self._save_file(os_path, model['content'], model.get('format')) - elif model['type'] == 'directory': - self._save_directory(os_path, model, path) - else: - raise web.HTTPError(400, "Unhandled contents type: %s" % model['type']) - except web.HTTPError: - raise - except Exception as e: - self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) - raise web.HTTPError(500, u'Unexpected error while saving file: %s %s' % - (path, e)) from e - - validation_message = None - if model['type'] == 'notebook': - self.validate_notebook_model(model) - validation_message = model.get('message', None) - - model = self.get(path, content=False) - if validation_message: - model['message'] = validation_message - - self.run_post_save_hook(model=model, os_path=os_path) - - return model - - def delete_file(self, path): - """Delete file at path.""" - path = path.strip('/') - os_path = self._get_os_path(path) - rm = os.unlink - if not os.path.exists(os_path): - raise web.HTTPError(404, u'File or directory does not exist: %s' % os_path) - - def is_non_empty_dir(os_path): - if os.path.isdir(os_path): - # A directory containing only leftover checkpoints is - # considered empty. - cp_dir = getattr(self.checkpoints, 'checkpoint_dir', None) - if set(os.listdir(os_path)) - {cp_dir}: - return True - - return False - - if self.delete_to_trash: - if sys.platform == 'win32' and is_non_empty_dir(os_path): - # send2trash can really delete files on Windows, so disallow - # deleting non-empty files. See Github issue 3631. - raise web.HTTPError(400, u'Directory %s not empty' % os_path) - try: - self.log.debug("Sending %s to trash", os_path) - send2trash(os_path) - return - except TrashPermissionError as e: - self.log.warning("Skipping trash for %s, %s", os_path, e) - - if os.path.isdir(os_path): - # Don't permanently delete non-empty directories. - if is_non_empty_dir(os_path): - raise web.HTTPError(400, u'Directory %s not empty' % os_path) - self.log.debug("Removing directory %s", os_path) - with self.perm_to_403(): - shutil.rmtree(os_path) - else: - self.log.debug("Unlinking file %s", os_path) - with self.perm_to_403(): - rm(os_path) - - def rename_file(self, old_path, new_path): - """Rename a file.""" - old_path = old_path.strip('/') - new_path = new_path.strip('/') - if new_path == old_path: - return - - # Perform path validation prior to converting to os-specific value since this - # is still relative to root_dir. - self._validate_path(new_path) - - new_os_path = self._get_os_path(new_path) - old_os_path = self._get_os_path(old_path) - - # Should we proceed with the move? - if os.path.exists(new_os_path) and not samefile(old_os_path, new_os_path): - raise web.HTTPError(409, u'File already exists: %s' % new_path) - - # Move the file - try: - with self.perm_to_403(): - shutil.move(old_os_path, new_os_path) - except web.HTTPError: - raise - except Exception as e: - raise web.HTTPError(500, u'Unknown error renaming file: %s %s' % - (old_path, e)) from e - - def info_string(self): - return _("Serving notebooks from local directory: %s") % self.root_dir - - def get_kernel_path(self, path, model=None): - """Return the initial API path of a kernel associated with a given notebook""" - if self.dir_exists(path): - return path - if '/' in path: - parent_dir = path.rsplit('/', 1)[0] - else: - parent_dir = '' - return parent_dir - - @staticmethod - def _validate_path(path): - """Checks if the path contains invalid characters relative to the current platform""" - - if sys.platform == 'win32': - # On Windows systems, we MUST disallow colons otherwise an Alternative Data Stream will - # be created and confusion will reign! (See https://github.com/jupyter/notebook/issues/5190) - # Go ahead and add other invalid (and non-path-separator) characters here as well so there's - # consistent behavior - although all others will result in '[Errno 22]Invalid Argument' errors. - invalid_chars = '?:><*"|' - else: - # On non-windows systems, allow the underlying file creation to perform enforcement when appropriate - invalid_chars = '' - - for char in invalid_chars: - if char in path: - raise web.HTTPError(400, "Path '{}' contains characters that are invalid for the filesystem. " - "Path names on this filesystem cannot contain any of the following " - "characters: {}".format(path, invalid_chars)) diff --git a/notebook/services/contents/handlers.py b/notebook/services/contents/handlers.py deleted file mode 100644 index b3216335b..000000000 --- a/notebook/services/contents/handlers.py +++ /dev/null @@ -1,332 +0,0 @@ -"""Tornado handlers for the contents web service. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-27%3A-Contents-Service -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import json - -from tornado import gen, web - -from notebook.utils import maybe_future, url_path_join, url_escape -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import ( - date_default as json_default - ) - -from notebook.base.handlers import ( - IPythonHandler, APIHandler, path_regex, -) - - -def validate_model(model, expect_content): - """ - Validate a model returned by a ContentsManager method. - - If expect_content is True, then we expect non-null entries for 'content' - and 'format'. - """ - required_keys = { - "name", - "path", - "type", - "writable", - "created", - "last_modified", - "mimetype", - "content", - "format", - } - missing = required_keys - set(model.keys()) - if missing: - raise web.HTTPError( - 500, - u"Missing Model Keys: {missing}".format(missing=missing), - ) - - maybe_none_keys = ['content', 'format'] - if expect_content: - errors = [key for key in maybe_none_keys if model[key] is None] - if errors: - raise web.HTTPError( - 500, - u"Keys unexpectedly None: {keys}".format(keys=errors), - ) - else: - errors = { - key: model[key] - for key in maybe_none_keys - if model[key] is not None - } - if errors: - raise web.HTTPError( - 500, - u"Keys unexpectedly not None: {keys}".format(keys=errors), - ) - - -class ContentsHandler(APIHandler): - - def location_url(self, path): - """Return the full URL location of a file. - - Parameters - ---------- - path : unicode - The API path of the file, such as "foo/bar.txt". - """ - return url_path_join( - self.base_url, 'api', 'contents', url_escape(path) - ) - - def _finish_model(self, model, location=True): - """Finish a JSON request with a model, setting relevant headers, etc.""" - if location: - location = self.location_url(model['path']) - self.set_header('Location', location) - self.set_header('Last-Modified', model['last_modified']) - self.set_header('Content-Type', 'application/json') - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @gen.coroutine - def get(self, path=''): - """Return a model for a file or directory. - - A directory model contains a list of models (without content) - of the files and directories it contains. - """ - path = path or '' - type = self.get_query_argument('type', default=None) - if type not in {None, 'directory', 'file', 'notebook'}: - raise web.HTTPError(400, u'Type %r is invalid' % type) - - format = self.get_query_argument('format', default=None) - if format not in {None, 'text', 'base64'}: - raise web.HTTPError(400, u'Format %r is invalid' % format) - content = self.get_query_argument('content', default='1') - if content not in {'0', '1'}: - raise web.HTTPError(400, u'Content %r is invalid' % content) - content = int(content) - - model = yield maybe_future(self.contents_manager.get( - path=path, type=type, format=format, content=content, - )) - validate_model(model, expect_content=content) - self._finish_model(model, location=False) - - @web.authenticated - @gen.coroutine - def patch(self, path=''): - """PATCH renames a file or directory without re-uploading content.""" - cm = self.contents_manager - model = self.get_json_body() - if model is None: - raise web.HTTPError(400, u'JSON body missing') - model = yield maybe_future(cm.update(model, path)) - validate_model(model, expect_content=False) - self._finish_model(model) - - @gen.coroutine - def _copy(self, copy_from, copy_to=None): - """Copy a file, optionally specifying a target directory.""" - self.log.info(u"Copying {copy_from} to {copy_to}".format( - copy_from=copy_from, - copy_to=copy_to or '', - )) - model = yield maybe_future(self.contents_manager.copy(copy_from, copy_to)) - self.set_status(201) - validate_model(model, expect_content=False) - self._finish_model(model) - - @gen.coroutine - def _upload(self, model, path): - """Handle upload of a new file to path""" - self.log.info(u"Uploading file to %s", path) - model = yield maybe_future(self.contents_manager.new(model, path)) - self.set_status(201) - validate_model(model, expect_content=False) - self._finish_model(model) - - @gen.coroutine - def _new_untitled(self, path, type='', ext=''): - """Create a new, empty untitled entity""" - self.log.info(u"Creating new %s in %s", type or 'file', path) - model = yield maybe_future(self.contents_manager.new_untitled(path=path, type=type, ext=ext)) - self.set_status(201) - validate_model(model, expect_content=False) - self._finish_model(model) - - @gen.coroutine - def _save(self, model, path): - """Save an existing file.""" - chunk = model.get("chunk", None) - if not chunk or chunk == -1: # Avoid tedious log information - self.log.info(u"Saving file at %s", path) - model = yield maybe_future(self.contents_manager.save(model, path)) - validate_model(model, expect_content=False) - self._finish_model(model) - - @web.authenticated - @gen.coroutine - def post(self, path=''): - """Create a new file in the specified path. - - POST creates new files. The server always decides on the name. - - POST /api/contents/path - New untitled, empty file or directory. - POST /api/contents/path - with body {"copy_from" : "/path/to/OtherNotebook.ipynb"} - New copy of OtherNotebook in path - """ - - cm = self.contents_manager - - file_exists = yield maybe_future(cm.file_exists(path)) - if file_exists: - raise web.HTTPError(400, "Cannot POST to files, use PUT instead.") - - dir_exists = yield maybe_future(cm.dir_exists(path)) - if not dir_exists: - raise web.HTTPError(404, "No such directory: %s" % path) - - model = self.get_json_body() - - if model is not None: - copy_from = model.get('copy_from') - ext = model.get('ext', '') - type = model.get('type', '') - if copy_from: - yield self._copy(copy_from, path) - else: - yield self._new_untitled(path, type=type, ext=ext) - else: - yield self._new_untitled(path) - - @web.authenticated - @gen.coroutine - def put(self, path=''): - """Saves the file in the location specified by name and path. - - PUT is very similar to POST, but the requester specifies the name, - whereas with POST, the server picks the name. - - PUT /api/contents/path/Name.ipynb - Save notebook at ``path/Name.ipynb``. Notebook structure is specified - in `content` key of JSON request body. If content is not specified, - create a new empty notebook. - """ - model = self.get_json_body() - if model: - if model.get('copy_from'): - raise web.HTTPError(400, "Cannot copy with PUT, only POST") - exists = yield maybe_future(self.contents_manager.file_exists(path)) - if exists: - yield maybe_future(self._save(model, path)) - else: - yield maybe_future(self._upload(model, path)) - else: - yield maybe_future(self._new_untitled(path)) - - @web.authenticated - @gen.coroutine - def delete(self, path=''): - """delete a file in the given path""" - cm = self.contents_manager - self.log.warning('delete %s', path) - yield maybe_future(cm.delete(path)) - self.set_status(204) - self.finish() - - -class CheckpointsHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self, path=''): - """get lists checkpoints for a file""" - cm = self.contents_manager - checkpoints = yield maybe_future(cm.list_checkpoints(path)) - data = json.dumps(checkpoints, default=json_default) - self.finish(data) - - @web.authenticated - @gen.coroutine - def post(self, path=''): - """post creates a new checkpoint""" - cm = self.contents_manager - checkpoint = yield maybe_future(cm.create_checkpoint(path)) - data = json.dumps(checkpoint, default=json_default) - location = url_path_join(self.base_url, 'api/contents', - url_escape(path), 'checkpoints', url_escape(checkpoint['id'])) - self.set_header('Location', location) - self.set_status(201) - self.finish(data) - - -class ModifyCheckpointsHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def post(self, path, checkpoint_id): - """post restores a file from a checkpoint""" - cm = self.contents_manager - yield maybe_future(cm.restore_checkpoint(checkpoint_id, path)) - self.set_status(204) - self.finish() - - @web.authenticated - @gen.coroutine - def delete(self, path, checkpoint_id): - """delete clears a checkpoint for a given file""" - cm = self.contents_manager - yield maybe_future(cm.delete_checkpoint(checkpoint_id, path)) - self.set_status(204) - self.finish() - - -class NotebooksRedirectHandler(IPythonHandler): - """Redirect /api/notebooks to /api/contents""" - SUPPORTED_METHODS = ('GET', 'PUT', 'PATCH', 'POST', 'DELETE') - - def get(self, path): - self.log.warning("/api/notebooks is deprecated, use /api/contents") - self.redirect(url_path_join( - self.base_url, - 'api/contents', - path - )) - - put = patch = post = delete = get - - -class TrustNotebooksHandler(IPythonHandler): - """ Handles trust/signing of notebooks """ - - @web.authenticated - @gen.coroutine - def post(self,path=''): - cm = self.contents_manager - yield maybe_future(cm.trust_notebook(path)) - self.set_status(201) - self.finish() -#----------------------------------------------------------------------------- -# URL to handler mappings -#----------------------------------------------------------------------------- - - -_checkpoint_id_regex = r"(?P[\w-]+)" - -default_handlers = [ - (r"/api/contents%s/checkpoints" % path_regex, CheckpointsHandler), - (r"/api/contents%s/checkpoints/%s" % (path_regex, _checkpoint_id_regex), - ModifyCheckpointsHandler), - (r"/api/contents%s/trust" % path_regex, TrustNotebooksHandler), - (r"/api/contents%s" % path_regex, ContentsHandler), - (r"/api/notebooks/?(.*)", NotebooksRedirectHandler), -] diff --git a/notebook/services/contents/largefilemanager.py b/notebook/services/contents/largefilemanager.py deleted file mode 100644 index 6779a0b5c..000000000 --- a/notebook/services/contents/largefilemanager.py +++ /dev/null @@ -1,70 +0,0 @@ -from notebook.services.contents.filemanager import FileContentsManager -from contextlib import contextmanager -from tornado import web -import nbformat -import base64 -import os, io - -class LargeFileManager(FileContentsManager): - """Handle large file upload.""" - - def save(self, model, path=''): - """Save the file model and return the model with no content.""" - chunk = model.get('chunk', None) - if chunk is not None: - path = path.strip('/') - - if 'type' not in model: - raise web.HTTPError(400, u'No file type provided') - if model['type'] != 'file': - raise web.HTTPError(400, u'File type "{}" is not supported for large file transfer'.format(model['type'])) - if 'content' not in model and model['type'] != 'directory': - raise web.HTTPError(400, u'No file content provided') - - os_path = self._get_os_path(path) - - try: - if chunk == 1: - self.log.debug("Saving %s", os_path) - self.run_pre_save_hook(model=model, path=path) - super()._save_file(os_path, model['content'], model.get('format')) - else: - self._save_large_file(os_path, model['content'], model.get('format')) - except web.HTTPError: - raise - except Exception as e: - self.log.error(u'Error while saving file: %s %s', path, e, exc_info=True) - raise web.HTTPError(500, u'Unexpected error while saving file: %s %s' % (path, e)) from e - - model = self.get(path, content=False) - - # Last chunk - if chunk == -1: - self.run_post_save_hook(model=model, os_path=os_path) - return model - else: - return super().save(model, path) - - def _save_large_file(self, os_path, content, format): - """Save content of a generic file.""" - if format not in {'text', 'base64'}: - raise web.HTTPError( - 400, - "Must specify format of file contents as 'text' or 'base64'", - ) - try: - if format == 'text': - bcontent = content.encode('utf8') - else: - b64_bytes = content.encode('ascii') - bcontent = base64.b64decode(b64_bytes) - except Exception as e: - raise web.HTTPError( - 400, u'Encoding error saving %s: %s' % (os_path, e) - ) from e - - with self.perm_to_403(os_path): - if os.path.islink(os_path): - os_path = os.path.join(os.path.dirname(os_path), os.readlink(os_path)) - with io.open(os_path, 'ab') as f: - f.write(bcontent) diff --git a/notebook/services/contents/manager.py b/notebook/services/contents/manager.py deleted file mode 100644 index b556abc1d..000000000 --- a/notebook/services/contents/manager.py +++ /dev/null @@ -1,532 +0,0 @@ -"""A base class for contents managers.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from fnmatch import fnmatch -import itertools -import json -import os -import re - -from tornado.web import HTTPError, RequestHandler - -from ...files.handlers import FilesHandler -from .checkpoints import Checkpoints -from traitlets.config.configurable import LoggingConfigurable -from nbformat import sign, validate as validate_nb, ValidationError -from nbformat.v4 import new_notebook -from ipython_genutils.importstring import import_item -from traitlets import ( - Any, - Bool, - Dict, - Instance, - List, - TraitError, - Type, - Unicode, - validate, - default, -) -from ipython_genutils.py3compat import string_types -from notebook.base.handlers import IPythonHandler -from notebook.transutils import _ - - -copy_pat = re.compile(r'\-Copy\d*\.') - - -class ContentsManager(LoggingConfigurable): - """Base class for serving files and directories. - - This serves any text or binary file, - as well as directories, - with special handling for JSON notebook documents. - - Most APIs take a path argument, - which is always an API-style unicode path, - and always refers to a directory. - - - unicode, not url-escaped - - '/'-separated - - leading and trailing '/' will be stripped - - if unspecified, path defaults to '', - indicating the root path. - - """ - - root_dir = Unicode('/', config=True) - - allow_hidden = Bool(False, config=True, help="Allow access to hidden files") - - notary = Instance(sign.NotebookNotary) - def _notary_default(self): - return sign.NotebookNotary(parent=self) - - hide_globs = List(Unicode(), [ - u'__pycache__', '*.pyc', '*.pyo', - '.DS_Store', '*.so', '*.dylib', '*~', - ], config=True, help=""" - Glob patterns to hide in file and directory listings. - """) - - untitled_notebook = Unicode(_("Untitled"), config=True, - help="The base name used when creating untitled notebooks." - ) - - untitled_file = Unicode("untitled", config=True, - help="The base name used when creating untitled files." - ) - - untitled_directory = Unicode("Untitled Folder", config=True, - help="The base name used when creating untitled directories." - ) - - pre_save_hook = Any(None, config=True, allow_none=True, - help="""Python callable or importstring thereof - - To be called on a contents model prior to save. - - This can be used to process the structure, - such as removing notebook outputs or other side effects that - should not be saved. - - It will be called as (all arguments passed by keyword):: - - hook(path=path, model=model, contents_manager=self) - - - model: the model to be saved. Includes file contents. - Modifying this dict will affect the file that is stored. - - path: the API path of the save destination - - contents_manager: this ContentsManager instance - """ - ) - - @validate('pre_save_hook') - def _validate_pre_save_hook(self, proposal): - value = proposal['value'] - if isinstance(value, string_types): - value = import_item(self.pre_save_hook) - if not callable(value): - raise TraitError("pre_save_hook must be callable") - return value - - def run_pre_save_hook(self, model, path, **kwargs): - """Run the pre-save hook if defined, and log errors""" - if self.pre_save_hook: - try: - self.log.debug("Running pre-save hook on %s", path) - self.pre_save_hook(model=model, path=path, contents_manager=self, **kwargs) - except Exception: - self.log.error("Pre-save hook failed on %s", path, exc_info=True) - - checkpoints_class = Type(Checkpoints, config=True) - checkpoints = Instance(Checkpoints, config=True) - checkpoints_kwargs = Dict(config=True) - - @default('checkpoints') - def _default_checkpoints(self): - return self.checkpoints_class(**self.checkpoints_kwargs) - - @default('checkpoints_kwargs') - def _default_checkpoints_kwargs(self): - return dict( - parent=self, - log=self.log, - ) - - files_handler_class = Type( - FilesHandler, klass=RequestHandler, allow_none=True, config=True, - help="""handler class to use when serving raw file requests. - - Default is a fallback that talks to the ContentsManager API, - which may be inefficient, especially for large files. - - Local files-based ContentsManagers can use a StaticFileHandler subclass, - which will be much more efficient. - - Access to these files should be Authenticated. - """ - ) - - files_handler_params = Dict( - config=True, - help="""Extra parameters to pass to files_handler_class. - - For example, StaticFileHandlers generally expect a `path` argument - specifying the root directory from which to serve files. - """ - ) - - def get_extra_handlers(self): - """Return additional handlers - - Default: self.files_handler_class on /files/.* - """ - handlers = [] - if self.files_handler_class: - handlers.append( - (r"/files/(.*)", self.files_handler_class, self.files_handler_params) - ) - return handlers - - # ContentsManager API part 1: methods that must be - # implemented in subclasses. - - def dir_exists(self, path): - """Does a directory exist at the given path? - - Like os.path.isdir - - Override this method in subclasses. - - Parameters - ---------- - path : string - The path to check - - Returns - ------- - exists : bool - Whether the path does indeed exist. - """ - raise NotImplementedError - - def is_hidden(self, path): - """Is path a hidden directory or file? - - Parameters - ---------- - path : string - The path to check. This is an API path (`/` separated, - relative to root dir). - - Returns - ------- - hidden : bool - Whether the path is hidden. - - """ - raise NotImplementedError - - def file_exists(self, path=''): - """Does a file exist at the given path? - - Like os.path.isfile - - Override this method in subclasses. - - Parameters - ---------- - path : string - The API path of a file to check for. - - Returns - ------- - exists : bool - Whether the file exists. - """ - raise NotImplementedError('must be implemented in a subclass') - - def exists(self, path): - """Does a file or directory exist at the given path? - - Like os.path.exists - - Parameters - ---------- - path : string - The API path of a file or directory to check for. - - Returns - ------- - exists : bool - Whether the target exists. - """ - return self.file_exists(path) or self.dir_exists(path) - - def get(self, path, content=True, type=None, format=None): - """Get a file or directory model.""" - raise NotImplementedError('must be implemented in a subclass') - - def save(self, model, path): - """ - Save a file or directory model to path. - - Should return the saved model with no content. Save implementations - should call self.run_pre_save_hook(model=model, path=path) prior to - writing any data. - """ - raise NotImplementedError('must be implemented in a subclass') - - def delete_file(self, path): - """Delete the file or directory at path.""" - raise NotImplementedError('must be implemented in a subclass') - - def rename_file(self, old_path, new_path): - """Rename a file or directory.""" - raise NotImplementedError('must be implemented in a subclass') - - # ContentsManager API part 2: methods that have useable default - # implementations, but can be overridden in subclasses. - - def delete(self, path): - """Delete a file/directory and any associated checkpoints.""" - path = path.strip('/') - if not path: - raise HTTPError(400, "Can't delete root") - self.delete_file(path) - self.checkpoints.delete_all_checkpoints(path) - - def rename(self, old_path, new_path): - """Rename a file and any checkpoints associated with that file.""" - self.rename_file(old_path, new_path) - self.checkpoints.rename_all_checkpoints(old_path, new_path) - - def update(self, model, path): - """Update the file's path - - For use in PATCH requests, to enable renaming a file without - re-uploading its contents. Only used for renaming at the moment. - """ - path = path.strip('/') - new_path = model.get('path', path).strip('/') - if path != new_path: - self.rename(path, new_path) - model = self.get(new_path, content=False) - return model - - def info_string(self): - return "Serving contents" - - def get_kernel_path(self, path, model=None): - """Return the API path for the kernel - - KernelManagers can turn this value into a filesystem path, - or ignore it altogether. - - The default value here will start kernels in the directory of the - notebook server. FileContentsManager overrides this to use the - directory containing the notebook. - """ - return '' - - def increment_filename(self, filename, path='', insert=''): - """Increment a filename until it is unique. - - Parameters - ---------- - filename : unicode - The name of a file, including extension - path : unicode - The API path of the target's directory - insert: unicode - The characters to insert after the base filename - - Returns - ------- - name : unicode - A filename that is unique, based on the input filename. - """ - # Extract the full suffix from the filename (e.g. .tar.gz) - path = path.strip('/') - basename, dot, ext = filename.rpartition('.') - if ext != 'ipynb': - basename, dot, ext = filename.partition('.') - - suffix = dot + ext - - for i in itertools.count(): - if i: - insert_i = '{}{}'.format(insert, i) - else: - insert_i = '' - name = u'{basename}{insert}{suffix}'.format(basename=basename, - insert=insert_i, suffix=suffix) - if not self.exists(u'{}/{}'.format(path, name)): - break - return name - - def validate_notebook_model(self, model): - """Add failed-validation message to model""" - try: - validate_nb(model['content']) - except ValidationError as e: - model['message'] = u'Notebook validation failed: {}:\n{}'.format( - e.message, json.dumps(e.instance, indent=1, default=lambda obj: ''), - ) - return model - - def new_untitled(self, path='', type='', ext=''): - """Create a new untitled file or directory in path - - path must be a directory - - File extension can be specified. - - Use `new` to create files with a fully specified path (including filename). - """ - path = path.strip('/') - if not self.dir_exists(path): - raise HTTPError(404, 'No such directory: %s' % path) - - model = {} - if type: - model['type'] = type - - if ext == '.ipynb': - model.setdefault('type', 'notebook') - else: - model.setdefault('type', 'file') - - insert = '' - if model['type'] == 'directory': - untitled = self.untitled_directory - insert = ' ' - elif model['type'] == 'notebook': - untitled = self.untitled_notebook - ext = '.ipynb' - elif model['type'] == 'file': - untitled = self.untitled_file - else: - raise HTTPError(400, "Unexpected model type: %r" % model['type']) - - name = self.increment_filename(untitled + ext, path, insert=insert) - path = u'{0}/{1}'.format(path, name) - return self.new(model, path) - - def new(self, model=None, path=''): - """Create a new file or directory and return its model with no content. - - To create a new untitled entity in a directory, use `new_untitled`. - """ - path = path.strip('/') - if model is None: - model = {} - - if path.endswith('.ipynb'): - model.setdefault('type', 'notebook') - else: - model.setdefault('type', 'file') - - # no content, not a directory, so fill out new-file model - if 'content' not in model and model['type'] != 'directory': - if model['type'] == 'notebook': - model['content'] = new_notebook() - model['format'] = 'json' - else: - model['content'] = '' - model['type'] = 'file' - model['format'] = 'text' - - model = self.save(model, path) - return model - - def copy(self, from_path, to_path=None): - """Copy an existing file and return its new model. - - If to_path not specified, it will be the parent directory of from_path. - If to_path is a directory, filename will increment `from_path-Copy#.ext`. - Considering multi-part extensions, the Copy# part will be placed before the first dot for all the extensions except `ipynb`. - For easier manual searching in case of notebooks, the Copy# part will be placed before the last dot. - - from_path must be a full path to a file. - """ - path = from_path.strip('/') - if to_path is not None: - to_path = to_path.strip('/') - - if '/' in path: - from_dir, from_name = path.rsplit('/', 1) - else: - from_dir = '' - from_name = path - - model = self.get(path) - model.pop('path', None) - model.pop('name', None) - if model['type'] == 'directory': - raise HTTPError(400, "Can't copy directories") - - if to_path is None: - to_path = from_dir - if self.dir_exists(to_path): - name = copy_pat.sub(u'.', from_name) - to_name = self.increment_filename(name, to_path, insert='-Copy') - to_path = u'{0}/{1}'.format(to_path, to_name) - - model = self.save(model, to_path) - return model - - def log_info(self): - self.log.info(self.info_string()) - - def trust_notebook(self, path): - """Explicitly trust a notebook - - Parameters - ---------- - path : string - The path of a notebook - """ - model = self.get(path) - nb = model['content'] - self.log.warning("Trusting notebook %s", path) - self.notary.mark_cells(nb, True) - self.check_and_sign(nb, path) - - def check_and_sign(self, nb, path=''): - """Check for trusted cells, and sign the notebook. - - Called as a part of saving notebooks. - - Parameters - ---------- - nb : dict - The notebook dict - path : string - The notebook's path (for logging) - """ - if self.notary.check_cells(nb): - self.notary.sign(nb) - else: - self.log.warning("Notebook %s is not trusted", path) - - def mark_trusted_cells(self, nb, path=''): - """Mark cells as trusted if the notebook signature matches. - - Called as a part of loading notebooks. - - Parameters - ---------- - nb : dict - The notebook object (in current nbformat) - path : string - The notebook's path (for logging) - """ - trusted = self.notary.check_signature(nb) - if not trusted: - self.log.warning("Notebook %s is not trusted", path) - self.notary.mark_cells(nb, trusted) - - def should_list(self, name): - """Should this file/directory name be displayed in a listing?""" - return not any(fnmatch(name, glob) for glob in self.hide_globs) - - # Part 3: Checkpoints API - def create_checkpoint(self, path): - """Create a checkpoint.""" - return self.checkpoints.create_checkpoint(self, path) - - def restore_checkpoint(self, checkpoint_id, path): - """ - Restore a checkpoint. - """ - self.checkpoints.restore_checkpoint(self, checkpoint_id, path) - - def list_checkpoints(self, path): - return self.checkpoints.list_checkpoints(path) - - def delete_checkpoint(self, checkpoint_id, path): - return self.checkpoints.delete_checkpoint(checkpoint_id, path) diff --git a/notebook/services/contents/tests/__init__.py b/notebook/services/contents/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/contents/tests/test_contents_api.py b/notebook/services/contents/tests/test_contents_api.py deleted file mode 100644 index 6e4ad49db..000000000 --- a/notebook/services/contents/tests/test_contents_api.py +++ /dev/null @@ -1,738 +0,0 @@ -"""Test the contents webservice API.""" - -from contextlib import contextmanager -from functools import partial -import io -import json -import os -import shutil -import sys -from unicodedata import normalize - -pjoin = os.path.join - -import requests -from send2trash import send2trash -from send2trash.exceptions import TrashPermissionError - -from ..filecheckpoints import GenericFileCheckpoints - -from traitlets.config import Config -from notebook.utils import url_path_join, url_escape, to_os_path -from notebook.tests.launchnotebook import NotebookTestBase, assert_http_error -from nbformat import write, from_dict -from nbformat.v4 import ( - new_notebook, new_markdown_cell, -) -from nbformat import v2 -from ipython_genutils import py3compat -from ipython_genutils.tempdir import TemporaryDirectory - -try: #PY3 - from base64 import encodebytes, decodebytes -except ImportError: #PY2 - from base64 import encodestring as encodebytes, decodestring as decodebytes - - -def uniq_stable(elems): - """uniq_stable(elems) -> list - - Return from an iterable, a list of all the unique elements in the input, - maintaining the order in which they first appear. - """ - seen = set() - return [x for x in elems if x not in seen and not seen.add(x)] - -def notebooks_only(dir_model): - return [nb for nb in dir_model['content'] if nb['type']=='notebook'] - -def dirs_only(dir_model): - return [x for x in dir_model['content'] if x['type']=='directory'] - - -class API(object): - """Wrapper for contents API calls.""" - def __init__(self, request): - self.request = request - - def _req(self, verb, path, body=None, params=None): - response = self.request(verb, - url_path_join('api/contents', path), - data=body, params=params, - ) - response.raise_for_status() - return response - - def list(self, path='/'): - return self._req('GET', path) - - def read(self, path, type=None, format=None, content=None): - params = {} - if type is not None: - params['type'] = type - if format is not None: - params['format'] = format - if content == False: - params['content'] = '0' - return self._req('GET', path, params=params) - - def create_untitled(self, path='/', ext='.ipynb'): - body = None - if ext: - body = json.dumps({'ext': ext}) - return self._req('POST', path, body) - - def mkdir_untitled(self, path='/'): - return self._req('POST', path, json.dumps({'type': 'directory'})) - - def copy(self, copy_from, path='/'): - body = json.dumps({'copy_from':copy_from}) - return self._req('POST', path, body) - - def create(self, path='/'): - return self._req('PUT', path) - - def upload(self, path, body): - return self._req('PUT', path, body) - - def mkdir(self, path='/'): - return self._req('PUT', path, json.dumps({'type': 'directory'})) - - def copy_put(self, copy_from, path='/'): - body = json.dumps({'copy_from':copy_from}) - return self._req('PUT', path, body) - - def save(self, path, body): - return self._req('PUT', path, body) - - def delete(self, path='/'): - return self._req('DELETE', path) - - def rename(self, path, new_path): - body = json.dumps({'path': new_path}) - return self._req('PATCH', path, body) - - def get_checkpoints(self, path): - return self._req('GET', url_path_join(path, 'checkpoints')) - - def new_checkpoint(self, path): - return self._req('POST', url_path_join(path, 'checkpoints')) - - def restore_checkpoint(self, path, checkpoint_id): - return self._req('POST', url_path_join(path, 'checkpoints', checkpoint_id)) - - def delete_checkpoint(self, path, checkpoint_id): - return self._req('DELETE', url_path_join(path, 'checkpoints', checkpoint_id)) - -class APITest(NotebookTestBase): - """Test the kernels web service API""" - dirs_nbs = [('', 'inroot'), - ('Directory with spaces in', 'inspace'), - (u'unicodé', 'innonascii'), - ('foo', 'a'), - ('foo', 'b'), - ('foo', 'name with spaces'), - ('foo', u'unicodé'), - ('foo/bar', 'baz'), - ('ordering', 'A'), - ('ordering', 'b'), - ('ordering', 'C'), - (u'å b', u'ç d'), - ] - hidden_dirs = ['.hidden', '__pycache__'] - - # Don't include root dir. - dirs = uniq_stable([py3compat.cast_unicode(d) for (d,n) in dirs_nbs[1:]]) - top_level_dirs = {normalize('NFC', d.split('/')[0]) for d in dirs} - - @staticmethod - def _blob_for_name(name): - return name.encode('utf-8') + b'\xFF' - - @staticmethod - def _txt_for_name(name): - return u'%s text file' % name - - def to_os_path(self, api_path): - return to_os_path(api_path, root=self.notebook_dir) - - def make_dir(self, api_path): - """Create a directory at api_path""" - os_path = self.to_os_path(api_path) - try: - os.makedirs(os_path) - except OSError: - print("Directory already exists: %r" % os_path) - - def make_txt(self, api_path, txt): - """Make a text file at a given api_path""" - os_path = self.to_os_path(api_path) - with io.open(os_path, 'w', encoding='utf-8') as f: - f.write(txt) - - def make_blob(self, api_path, blob): - """Make a binary file at a given api_path""" - os_path = self.to_os_path(api_path) - with io.open(os_path, 'wb') as f: - f.write(blob) - - def make_nb(self, api_path, nb): - """Make a notebook file at a given api_path""" - os_path = self.to_os_path(api_path) - - with io.open(os_path, 'w', encoding='utf-8') as f: - write(nb, f, version=4) - - def delete_dir(self, api_path): - """Delete a directory at api_path, removing any contents.""" - os_path = self.to_os_path(api_path) - shutil.rmtree(os_path, ignore_errors=True) - - def delete_file(self, api_path): - """Delete a file at the given path if it exists.""" - if self.isfile(api_path): - os.unlink(self.to_os_path(api_path)) - - def isfile(self, api_path): - return os.path.isfile(self.to_os_path(api_path)) - - def isdir(self, api_path): - return os.path.isdir(self.to_os_path(api_path)) - - def can_send2trash(self, api_path): - """Send a path to trash, if possible. Return success.""" - try: - send2trash(self.to_os_path(api_path)) - return True - except TrashPermissionError as e: - return False - - def setUp(self): - for d in (self.dirs + self.hidden_dirs): - self.make_dir(d) - self.addCleanup(partial(self.delete_dir, d)) - - for d, name in self.dirs_nbs: - # create a notebook - nb = new_notebook() - nbname = u'{}/{}.ipynb'.format(d, name) - self.make_nb(nbname, nb) - self.addCleanup(partial(self.delete_file, nbname)) - - # create a text file - txt = self._txt_for_name(name) - txtname = u'{}/{}.txt'.format(d, name) - self.make_txt(txtname, txt) - self.addCleanup(partial(self.delete_file, txtname)) - - blob = self._blob_for_name(name) - blobname = u'{}/{}.blob'.format(d, name) - self.make_blob(blobname, blob) - self.addCleanup(partial(self.delete_file, blobname)) - - self.api = API(self.request) - - def test_list_notebooks(self): - nbs = notebooks_only(self.api.list().json()) - self.assertEqual(len(nbs), 1) - self.assertEqual(nbs[0]['name'], 'inroot.ipynb') - - nbs = notebooks_only(self.api.list('/Directory with spaces in/').json()) - self.assertEqual(len(nbs), 1) - self.assertEqual(nbs[0]['name'], 'inspace.ipynb') - - nbs = notebooks_only(self.api.list(u'/unicodé/').json()) - self.assertEqual(len(nbs), 1) - self.assertEqual(nbs[0]['name'], 'innonascii.ipynb') - self.assertEqual(nbs[0]['path'], u'unicodé/innonascii.ipynb') - - nbs = notebooks_only(self.api.list('/foo/bar/').json()) - self.assertEqual(len(nbs), 1) - self.assertEqual(nbs[0]['name'], 'baz.ipynb') - self.assertEqual(nbs[0]['path'], 'foo/bar/baz.ipynb') - - nbs = notebooks_only(self.api.list('foo').json()) - self.assertEqual(len(nbs), 4) - nbnames = { normalize('NFC', n['name']) for n in nbs } - expected = [ u'a.ipynb', u'b.ipynb', u'name with spaces.ipynb', u'unicodé.ipynb'] - expected = { normalize('NFC', name) for name in expected } - self.assertEqual(nbnames, expected) - - nbs = notebooks_only(self.api.list('ordering').json()) - nbnames = {n['name'] for n in nbs} - expected = {'A.ipynb', 'b.ipynb', 'C.ipynb'} - self.assertEqual(nbnames, expected) - - def test_list_dirs(self): - dirs = dirs_only(self.api.list().json()) - dir_names = {normalize('NFC', d['name']) for d in dirs} - self.assertEqual(dir_names, self.top_level_dirs) # Excluding hidden dirs - - def test_get_dir_no_content(self): - for d in self.dirs: - model = self.api.read(d, content=False).json() - self.assertEqual(model['path'], d) - self.assertEqual(model['type'], 'directory') - self.assertIn('content', model) - self.assertEqual(model['content'], None) - - def test_list_nonexistant_dir(self): - with assert_http_error(404): - self.api.list('nonexistant') - - def test_get_nb_contents(self): - for d, name in self.dirs_nbs: - path = url_path_join(d, name + '.ipynb') - nb = self.api.read(path).json() - self.assertEqual(nb['name'], u'%s.ipynb' % name) - self.assertEqual(nb['path'], path) - self.assertEqual(nb['type'], 'notebook') - self.assertIn('content', nb) - self.assertEqual(nb['format'], 'json') - self.assertIn('metadata', nb['content']) - self.assertIsInstance(nb['content']['metadata'], dict) - - def test_get_nb_no_content(self): - for d, name in self.dirs_nbs: - path = url_path_join(d, name + '.ipynb') - nb = self.api.read(path, content=False).json() - self.assertEqual(nb['name'], u'%s.ipynb' % name) - self.assertEqual(nb['path'], path) - self.assertEqual(nb['type'], 'notebook') - self.assertIn('content', nb) - self.assertEqual(nb['content'], None) - - def test_get_nb_invalid(self): - nb = { - 'nbformat': 4, - 'metadata': {}, - 'cells': [{ - 'cell_type': 'wrong', - 'metadata': {}, - }], - } - path = u'å b/Validate tést.ipynb' - self.make_txt(path, py3compat.cast_unicode(json.dumps(nb))) - model = self.api.read(path).json() - self.assertEqual(model['path'], path) - self.assertEqual(model['type'], 'notebook') - self.assertIn('content', model) - self.assertIn('message', model) - self.assertIn("validation failed", model['message'].lower()) - - def test_get_contents_no_such_file(self): - # Name that doesn't exist - should be a 404 - with assert_http_error(404): - self.api.read('foo/q.ipynb') - - def test_get_text_file_contents(self): - for d, name in self.dirs_nbs: - path = url_path_join(d, name + '.txt') - model = self.api.read(path).json() - self.assertEqual(model['name'], u'%s.txt' % name) - self.assertEqual(model['path'], path) - self.assertIn('content', model) - self.assertEqual(model['format'], 'text') - self.assertEqual(model['type'], 'file') - self.assertEqual(model['content'], self._txt_for_name(name)) - - # Name that doesn't exist - should be a 404 - with assert_http_error(404): - self.api.read('foo/q.txt') - - # Specifying format=text should fail on a non-UTF-8 file - with assert_http_error(400): - self.api.read('foo/bar/baz.blob', type='file', format='text') - - def test_get_binary_file_contents(self): - for d, name in self.dirs_nbs: - path = url_path_join(d, name + '.blob') - model = self.api.read(path).json() - self.assertEqual(model['name'], u'%s.blob' % name) - self.assertEqual(model['path'], path) - self.assertIn('content', model) - self.assertEqual(model['format'], 'base64') - self.assertEqual(model['type'], 'file') - self.assertEqual( - decodebytes(model['content'].encode('ascii')), - self._blob_for_name(name), - ) - - # Name that doesn't exist - should be a 404 - with assert_http_error(404): - self.api.read('foo/q.txt') - - def test_get_bad_type(self): - with assert_http_error(400): - self.api.read(u'unicodé', type='file') # this is a directory - - with assert_http_error(400): - self.api.read(u'unicodé/innonascii.ipynb', type='directory') - - def _check_created(self, resp, path, type='notebook'): - self.assertEqual(resp.status_code, 201) - location_header = py3compat.str_to_unicode(resp.headers['Location']) - self.assertEqual(location_header, url_path_join(self.url_prefix, u'api/contents', url_escape(path))) - rjson = resp.json() - self.assertEqual(rjson['name'], path.rsplit('/', 1)[-1]) - self.assertEqual(rjson['path'], path) - self.assertEqual(rjson['type'], type) - isright = self.isdir if type == 'directory' else self.isfile - assert isright(path) - - def test_create_untitled(self): - resp = self.api.create_untitled(path=u'å b') - self._check_created(resp, u'å b/Untitled.ipynb') - - # Second time - resp = self.api.create_untitled(path=u'å b') - self._check_created(resp, u'å b/Untitled1.ipynb') - - # And two directories down - resp = self.api.create_untitled(path='foo/bar') - self._check_created(resp, 'foo/bar/Untitled.ipynb') - - def test_create_untitled_txt(self): - resp = self.api.create_untitled(path='foo/bar', ext='.txt') - self._check_created(resp, 'foo/bar/untitled.txt', type='file') - - resp = self.api.read(path='foo/bar/untitled.txt') - model = resp.json() - self.assertEqual(model['type'], 'file') - self.assertEqual(model['format'], 'text') - self.assertEqual(model['content'], '') - - def test_upload(self): - nb = new_notebook() - nbmodel = {'content': nb, 'type': 'notebook'} - path = u'å b/Upload tést.ipynb' - resp = self.api.upload(path, body=json.dumps(nbmodel)) - self._check_created(resp, path) - - def test_mkdir_untitled(self): - resp = self.api.mkdir_untitled(path=u'å b') - self._check_created(resp, u'å b/Untitled Folder', type='directory') - - # Second time - resp = self.api.mkdir_untitled(path=u'å b') - self._check_created(resp, u'å b/Untitled Folder 1', type='directory') - - # And two directories down - resp = self.api.mkdir_untitled(path='foo/bar') - self._check_created(resp, 'foo/bar/Untitled Folder', type='directory') - - def test_mkdir(self): - path = u'å b/New ∂ir' - resp = self.api.mkdir(path) - self._check_created(resp, path, type='directory') - - def test_mkdir_hidden_400(self): - with assert_http_error(400): - resp = self.api.mkdir(u'å b/.hidden') - - def test_upload_txt(self): - body = u'ünicode téxt' - model = { - 'content' : body, - 'format' : 'text', - 'type' : 'file', - } - path = u'å b/Upload tést.txt' - resp = self.api.upload(path, body=json.dumps(model)) - - # check roundtrip - resp = self.api.read(path) - model = resp.json() - self.assertEqual(model['type'], 'file') - self.assertEqual(model['format'], 'text') - self.assertEqual(model['content'], body) - - def test_upload_b64(self): - body = b'\xFFblob' - b64body = encodebytes(body).decode('ascii') - model = { - 'content' : b64body, - 'format' : 'base64', - 'type' : 'file', - } - path = u'å b/Upload tést.blob' - resp = self.api.upload(path, body=json.dumps(model)) - - # check roundtrip - resp = self.api.read(path) - model = resp.json() - self.assertEqual(model['type'], 'file') - self.assertEqual(model['path'], path) - self.assertEqual(model['format'], 'base64') - decoded = decodebytes(model['content'].encode('ascii')) - self.assertEqual(decoded, body) - - def test_upload_v2(self): - nb = v2.new_notebook() - ws = v2.new_worksheet() - nb.worksheets.append(ws) - ws.cells.append(v2.new_code_cell(input='print("hi")')) - nbmodel = {'content': nb, 'type': 'notebook'} - path = u'å b/Upload tést.ipynb' - resp = self.api.upload(path, body=json.dumps(nbmodel)) - self._check_created(resp, path) - resp = self.api.read(path) - data = resp.json() - self.assertEqual(data['content']['nbformat'], 4) - - def test_copy(self): - resp = self.api.copy(u'å b/ç d.ipynb', u'å b') - self._check_created(resp, u'å b/ç d-Copy1.ipynb') - - resp = self.api.copy(u'å b/ç d.ipynb', u'å b') - self._check_created(resp, u'å b/ç d-Copy2.ipynb') - - def test_copy_copy(self): - resp = self.api.copy(u'å b/ç d.ipynb', u'å b') - self._check_created(resp, u'å b/ç d-Copy1.ipynb') - - resp = self.api.copy(u'å b/ç d-Copy1.ipynb', u'å b') - self._check_created(resp, u'å b/ç d-Copy2.ipynb') - - def test_copy_path(self): - resp = self.api.copy(u'foo/a.ipynb', u'å b') - self._check_created(resp, u'å b/a.ipynb') - - resp = self.api.copy(u'foo/a.ipynb', u'å b') - self._check_created(resp, u'å b/a-Copy1.ipynb') - - def test_copy_put_400(self): - with assert_http_error(400): - resp = self.api.copy_put(u'å b/ç d.ipynb', u'å b/cøpy.ipynb') - - def test_copy_dir_400(self): - # can't copy directories - with assert_http_error(400): - resp = self.api.copy(u'å b', u'foo') - - def test_delete(self): - for d, name in self.dirs_nbs: - print('%r, %r' % (d, name)) - resp = self.api.delete(url_path_join(d, name + '.ipynb')) - self.assertEqual(resp.status_code, 204) - - for d in self.dirs + ['/']: - nbs = notebooks_only(self.api.list(d).json()) - print('------') - print(d) - print(nbs) - self.assertEqual(nbs, []) - - def test_delete_dirs(self): - # depth-first delete everything, so we don't try to delete empty directories - for name in sorted(self.dirs + ['/'], key=len, reverse=True): - listing = self.api.list(name).json()['content'] - for model in listing: - self.api.delete(model['path']) - listing = self.api.list('/').json()['content'] - self.assertEqual(listing, []) - - def test_delete_non_empty_dir(self): - if sys.platform == 'win32': - self.skipTest("Disabled deleting non-empty dirs on Windows") - # Test that non empty directory can be deleted - try: - self.api.delete(u'å b') - except requests.HTTPError as e: - if e.response.status_code == 400: - if not self.can_send2trash(u'å b'): - self.skipTest("Dir can't be sent to trash") - raise - # Check if directory has actually been deleted - with assert_http_error(404): - self.api.list(u'å b') - - def test_rename(self): - resp = self.api.rename('foo/a.ipynb', 'foo/z.ipynb') - self.assertEqual(resp.headers['Location'].split('/')[-1], 'z.ipynb') - self.assertEqual(resp.json()['name'], 'z.ipynb') - self.assertEqual(resp.json()['path'], 'foo/z.ipynb') - assert self.isfile('foo/z.ipynb') - - nbs = notebooks_only(self.api.list('foo').json()) - nbnames = set(n['name'] for n in nbs) - self.assertIn('z.ipynb', nbnames) - self.assertNotIn('a.ipynb', nbnames) - - def test_checkpoints_follow_file(self): - - # Read initial file state - orig = self.api.read('foo/a.ipynb') - - # Create a checkpoint of initial state - r = self.api.new_checkpoint('foo/a.ipynb') - cp1 = r.json() - - # Modify file and save - nbcontent = json.loads(orig.text)['content'] - nb = from_dict(nbcontent) - hcell = new_markdown_cell('Created by test') - nb.cells.append(hcell) - nbmodel = {'content': nb, 'type': 'notebook'} - self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) - - # Rename the file. - self.api.rename('foo/a.ipynb', 'foo/z.ipynb') - - # Looking for checkpoints in the old location should yield no results. - self.assertEqual(self.api.get_checkpoints('foo/a.ipynb').json(), []) - - # Looking for checkpoints in the new location should work. - cps = self.api.get_checkpoints('foo/z.ipynb').json() - self.assertEqual(cps, [cp1]) - - # Delete the file. The checkpoint should be deleted as well. - self.api.delete('foo/z.ipynb') - cps = self.api.get_checkpoints('foo/z.ipynb').json() - self.assertEqual(cps, []) - - def test_rename_existing(self): - with assert_http_error(409): - self.api.rename('foo/a.ipynb', 'foo/b.ipynb') - - def test_save(self): - resp = self.api.read('foo/a.ipynb') - nbcontent = json.loads(resp.text)['content'] - nb = from_dict(nbcontent) - nb.cells.append(new_markdown_cell(u'Created by test ³')) - - nbmodel = {'content': nb, 'type': 'notebook'} - resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) - - nbcontent = self.api.read('foo/a.ipynb').json()['content'] - newnb = from_dict(nbcontent) - self.assertEqual(newnb.cells[0].source, - u'Created by test ³') - - def test_checkpoints(self): - resp = self.api.read('foo/a.ipynb') - r = self.api.new_checkpoint('foo/a.ipynb') - self.assertEqual(r.status_code, 201) - cp1 = r.json() - self.assertEqual(set(cp1), {'id', 'last_modified'}) - self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id']) - - # Modify it - nbcontent = json.loads(resp.text)['content'] - nb = from_dict(nbcontent) - hcell = new_markdown_cell('Created by test') - nb.cells.append(hcell) - # Save - nbmodel= {'content': nb, 'type': 'notebook'} - resp = self.api.save('foo/a.ipynb', body=json.dumps(nbmodel)) - - # List checkpoints - cps = self.api.get_checkpoints('foo/a.ipynb').json() - self.assertEqual(cps, [cp1]) - - nbcontent = self.api.read('foo/a.ipynb').json()['content'] - nb = from_dict(nbcontent) - self.assertEqual(nb.cells[0].source, 'Created by test') - - # Restore cp1 - r = self.api.restore_checkpoint('foo/a.ipynb', cp1['id']) - self.assertEqual(r.status_code, 204) - nbcontent = self.api.read('foo/a.ipynb').json()['content'] - nb = from_dict(nbcontent) - self.assertEqual(nb.cells, []) - - # Delete cp1 - r = self.api.delete_checkpoint('foo/a.ipynb', cp1['id']) - self.assertEqual(r.status_code, 204) - cps = self.api.get_checkpoints('foo/a.ipynb').json() - self.assertEqual(cps, []) - - def test_file_checkpoints(self): - """ - Test checkpointing of non-notebook files. - """ - filename = 'foo/a.txt' - resp = self.api.read(filename) - orig_content = json.loads(resp.text)['content'] - - # Create a checkpoint. - r = self.api.new_checkpoint(filename) - self.assertEqual(r.status_code, 201) - cp1 = r.json() - self.assertEqual(set(cp1), {'id', 'last_modified'}) - self.assertEqual(r.headers['Location'].split('/')[-1], cp1['id']) - - # Modify the file and save. - new_content = orig_content + '\nsecond line' - model = { - 'content': new_content, - 'type': 'file', - 'format': 'text', - } - resp = self.api.save(filename, body=json.dumps(model)) - - # List checkpoints - cps = self.api.get_checkpoints(filename).json() - self.assertEqual(cps, [cp1]) - - content = self.api.read(filename).json()['content'] - self.assertEqual(content, new_content) - - # Restore cp1 - r = self.api.restore_checkpoint(filename, cp1['id']) - self.assertEqual(r.status_code, 204) - restored_content = self.api.read(filename).json()['content'] - self.assertEqual(restored_content, orig_content) - - # Delete cp1 - r = self.api.delete_checkpoint(filename, cp1['id']) - self.assertEqual(r.status_code, 204) - cps = self.api.get_checkpoints(filename).json() - self.assertEqual(cps, []) - - @contextmanager - def patch_cp_root(self, dirname): - """ - Temporarily patch the root dir of our checkpoint manager. - """ - cpm = self.notebook.contents_manager.checkpoints - old_dirname = cpm.root_dir - cpm.root_dir = dirname - try: - yield - finally: - cpm.root_dir = old_dirname - - def test_checkpoints_separate_root(self): - """ - Test that FileCheckpoints functions correctly even when it's - using a different root dir from FileContentsManager. This also keeps - the implementation honest for use with ContentsManagers that don't map - models to the filesystem - - Override this method to a no-op when testing other managers. - """ - with TemporaryDirectory() as td: - with self.patch_cp_root(td): - self.test_checkpoints() - - with TemporaryDirectory() as td: - with self.patch_cp_root(td): - self.test_file_checkpoints() - - -class GenericFileCheckpointsAPITest(APITest): - """ - Run the tests from APITest with GenericFileCheckpoints. - """ - config = Config() - config.FileContentsManager.checkpoints_class = GenericFileCheckpoints - - def test_config_did_something(self): - - self.assertIsInstance( - self.notebook.contents_manager.checkpoints, - GenericFileCheckpoints, - ) - - diff --git a/notebook/services/contents/tests/test_fileio.py b/notebook/services/contents/tests/test_fileio.py deleted file mode 100644 index adc06d97f..000000000 --- a/notebook/services/contents/tests/test_fileio.py +++ /dev/null @@ -1,132 +0,0 @@ -"""Tests for file IO""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import io as stdlib_io -import os.path -import unittest -import pytest -import stat -import sys - -from ..fileio import atomic_writing - -from ipython_genutils.tempdir import TemporaryDirectory - -umask = 0 - -def test_atomic_writing(): - class CustomExc(Exception): pass - - with TemporaryDirectory() as td: - f1 = os.path.join(td, 'penguin') - with stdlib_io.open(f1, 'w') as f: - f.write(u'Before') - - if os.name != 'nt': - os.chmod(f1, 0o701) - orig_mode = stat.S_IMODE(os.stat(f1).st_mode) - - f2 = os.path.join(td, 'flamingo') - try: - os.symlink(f1, f2) - have_symlink = True - except (AttributeError, NotImplementedError, OSError): - # AttributeError: Python doesn't support it - # NotImplementedError: The system doesn't support it - # OSError: The user lacks the privilege (Windows) - have_symlink = False - - with pytest.raises(CustomExc): - with atomic_writing(f1) as f: - f.write(u'Failing write') - raise CustomExc - - # Because of the exception, the file should not have been modified - with stdlib_io.open(f1, 'r') as f: - assert f.read() == u'Before' - - with atomic_writing(f1) as f: - f.write(u'Overwritten') - - with stdlib_io.open(f1, 'r') as f: - assert f.read() == u'Overwritten' - - if os.name != 'nt': - mode = stat.S_IMODE(os.stat(f1).st_mode) - assert mode == orig_mode - - if have_symlink: - # Check that writing over a file preserves a symlink - with atomic_writing(f2) as f: - f.write(u'written from symlink') - - with stdlib_io.open(f1, 'r') as f: - assert f.read() == u'written from symlink' - -class TestWithSetUmask(unittest.TestCase): - def setUp(self): - # save umask - global umask - umask = os.umask(0) - os.umask(umask) - - def tearDown(self): - # restore umask - os.umask(umask) - - @pytest.mark.skipif(sys.platform == "win32", reason="do not run on windows") - def test_atomic_writing_umask(self): - with TemporaryDirectory() as td: - os.umask(0o022) - f1 = os.path.join(td, '1') - with atomic_writing(f1) as f: - f.write(u'1') - mode = stat.S_IMODE(os.stat(f1).st_mode) - assert mode == 0o644 - - os.umask(0o057) - f2 = os.path.join(td, '2') - with atomic_writing(f2) as f: - f.write(u'2') - mode = stat.S_IMODE(os.stat(f2).st_mode) - assert mode == 0o620 - - -def test_atomic_writing_newlines(): - with TemporaryDirectory() as td: - path = os.path.join(td, 'testfile') - - lf = u'a\nb\nc\n' - plat = lf.replace(u'\n', os.linesep) - crlf = lf.replace(u'\n', u'\r\n') - - # test default - with stdlib_io.open(path, 'w') as f: - f.write(lf) - with stdlib_io.open(path, 'r', newline='') as f: - read = f.read() - assert read == plat - - # test newline=LF - with stdlib_io.open(path, 'w', newline='\n') as f: - f.write(lf) - with stdlib_io.open(path, 'r', newline='') as f: - read = f.read() - assert read == lf - - # test newline=CRLF - with atomic_writing(path, newline='\r\n') as f: - f.write(lf) - with stdlib_io.open(path, 'r', newline='') as f: - read = f.read() - assert read == crlf - - # test newline=no convert - text = u'crlf\r\ncr\rlf\n' - with atomic_writing(path, newline='') as f: - f.write(text) - with stdlib_io.open(path, 'r', newline='') as f: - read = f.read() - assert read == text diff --git a/notebook/services/contents/tests/test_largefilemanager.py b/notebook/services/contents/tests/test_largefilemanager.py deleted file mode 100644 index 13d294b9b..000000000 --- a/notebook/services/contents/tests/test_largefilemanager.py +++ /dev/null @@ -1,113 +0,0 @@ -from unittest import TestCase -from ipython_genutils.tempdir import TemporaryDirectory -from ..largefilemanager import LargeFileManager -import os -from tornado import web - - -def _make_dir(contents_manager, api_path): - """ - Make a directory. - """ - os_path = contents_manager._get_os_path(api_path) - try: - os.makedirs(os_path) - except OSError: - print("Directory already exists: %r" % os_path) - - -class TestLargeFileManager(TestCase): - - def setUp(self): - self._temp_dir = TemporaryDirectory() - self.td = self._temp_dir.name - self.contents_manager = LargeFileManager(root_dir=self.td) - - def make_dir(self, api_path): - """make a subdirectory at api_path - - override in subclasses if contents are not on the filesystem. - """ - _make_dir(self.contents_manager, api_path) - - def test_save(self): - - cm = self.contents_manager - # Create a notebook - model = cm.new_untitled(type='notebook') - name = model['name'] - path = model['path'] - - # Get the model with 'content' - full_model = cm.get(path) - # Save the notebook - model = cm.save(full_model, path) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertEqual(model['name'], name) - self.assertEqual(model['path'], path) - - try: - model = {'name': 'test', 'path': 'test', 'chunk': 1} - cm.save(model, model['path']) - except web.HTTPError as e: - self.assertEqual('HTTP 400: Bad Request (No file type provided)', str(e)) - - try: - model = {'name': 'test', 'path': 'test', 'chunk': 1, 'type': 'notebook'} - cm.save(model, model['path']) - except web.HTTPError as e: - self.assertEqual('HTTP 400: Bad Request (File type "notebook" is not supported for large file transfer)', str(e)) - - try: - model = {'name': 'test', 'path': 'test', 'chunk': 1, 'type': 'file'} - cm.save(model, model['path']) - except web.HTTPError as e: - self.assertEqual('HTTP 400: Bad Request (No file content provided)', str(e)) - - try: - model = {'name': 'test', 'path': 'test', 'chunk': 2, 'type': 'file', - 'content': u'test', 'format': 'json'} - cm.save(model, model['path']) - except web.HTTPError as e: - self.assertEqual("HTTP 400: Bad Request (Must specify format of file contents as 'text' or 'base64')", - str(e)) - - # Save model for different chunks - model = {'name': 'test', 'path': 'test', 'type': 'file', - 'content': u'test==', 'format': 'text'} - name = model['name'] - path = model['path'] - cm.save(model, path) - - for chunk in (1, 2, -1): - for fm in ('text', 'base64'): - full_model = cm.get(path) - full_model['chunk'] = chunk - full_model['format'] = fm - model_res = cm.save(full_model, path) - assert isinstance(model_res, dict) - - self.assertIn('name', model_res) - self.assertIn('path', model_res) - self.assertNotIn('chunk', model_res) - self.assertEqual(model_res['name'], name) - self.assertEqual(model_res['path'], path) - - # Test in sub-directory - # Create a directory and notebook in that directory - sub_dir = '/foo/' - self.make_dir('foo') - model = cm.new_untitled(path=sub_dir, type='notebook') - name = model['name'] - path = model['path'] - model = cm.get(path) - - # Change the name in the model for rename - model = cm.save(model, path) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertEqual(model['name'], 'Untitled.ipynb') - self.assertEqual(model['path'], 'foo/Untitled.ipynb') diff --git a/notebook/services/contents/tests/test_manager.py b/notebook/services/contents/tests/test_manager.py deleted file mode 100644 index dfe5d272f..000000000 --- a/notebook/services/contents/tests/test_manager.py +++ /dev/null @@ -1,658 +0,0 @@ -"""Tests for the notebook manager.""" - -import os -import sys -import time -from contextlib import contextmanager -from itertools import combinations - -from tornado.web import HTTPError -from unittest import TestCase, skipIf -from tempfile import NamedTemporaryFile - -from nbformat import v4 as nbformat - -from ipython_genutils.tempdir import TemporaryDirectory -from traitlets import TraitError - -from ..filemanager import FileContentsManager - - -def _make_dir(contents_manager, api_path): - """ - Make a directory. - """ - os_path = contents_manager._get_os_path(api_path) - try: - os.makedirs(os_path) - except OSError: - print("Directory already exists: %r" % os_path) - - -class TestFileContentsManager(TestCase): - - @contextmanager - def assertRaisesHTTPError(self, status, msg=None): - msg = msg or "Should have raised HTTPError(%i)" % status - try: - yield - except HTTPError as e: - self.assertEqual(e.status_code, status) - else: - self.fail(msg) - - def symlink(self, contents_manager, src, dst): - """Make a symlink to src from dst - - src and dst are api_paths - """ - src_os_path = contents_manager._get_os_path(src) - dst_os_path = contents_manager._get_os_path(dst) - print(src_os_path, dst_os_path, os.path.isfile(src_os_path)) - os.symlink(src_os_path, dst_os_path) - - def test_root_dir(self): - with TemporaryDirectory() as td: - fm = FileContentsManager(root_dir=td) - self.assertEqual(fm.root_dir, td) - - def test_missing_root_dir(self): - with TemporaryDirectory() as td: - root = os.path.join(td, 'notebook', 'dir', 'is', 'missing') - self.assertRaises(TraitError, FileContentsManager, root_dir=root) - - def test_invalid_root_dir(self): - with NamedTemporaryFile() as tf: - self.assertRaises(TraitError, FileContentsManager, root_dir=tf.name) - - def test_get_os_path(self): - # full filesystem path should be returned with correct operating system - # separators. - with TemporaryDirectory() as td: - root = td - fm = FileContentsManager(root_dir=root) - path = fm._get_os_path('/path/to/notebook/test.ipynb') - rel_path_list = '/path/to/notebook/test.ipynb'.split('/') - fs_path = os.path.join(fm.root_dir, *rel_path_list) - self.assertEqual(path, fs_path) - - fm = FileContentsManager(root_dir=root) - path = fm._get_os_path('test.ipynb') - fs_path = os.path.join(fm.root_dir, 'test.ipynb') - self.assertEqual(path, fs_path) - - fm = FileContentsManager(root_dir=root) - path = fm._get_os_path('////test.ipynb') - fs_path = os.path.join(fm.root_dir, 'test.ipynb') - self.assertEqual(path, fs_path) - - def test_checkpoint_subdir(self): - subd = u'sub ∂ir' - cp_name = 'test-cp.ipynb' - with TemporaryDirectory() as td: - root = td - os.mkdir(os.path.join(td, subd)) - fm = FileContentsManager(root_dir=root) - cpm = fm.checkpoints - cp_dir = cpm.checkpoint_path( - 'cp', 'test.ipynb' - ) - cp_subdir = cpm.checkpoint_path( - 'cp', '/%s/test.ipynb' % subd - ) - self.assertNotEqual(cp_dir, cp_subdir) - self.assertEqual(cp_dir, os.path.join(root, cpm.checkpoint_dir, cp_name)) - self.assertEqual(cp_subdir, os.path.join(root, subd, cpm.checkpoint_dir, cp_name)) - - def test_bad_symlink(self): - with TemporaryDirectory() as td: - cm = FileContentsManager(root_dir=td) - path = 'test bad symlink' - _make_dir(cm, path) - - file_model = cm.new_untitled(path=path, ext='.txt') - - # create a broken symlink - self.symlink(cm, "target", '%s/%s' % (path, 'bad symlink')) - model = cm.get(path) - - contents = { - content['name']: content for content in model['content'] - } - self.assertTrue('untitled.txt' in contents) - self.assertEqual(contents['untitled.txt'], file_model) - # broken symlinks should still be shown in the contents manager - self.assertTrue('bad symlink' in contents) - - @skipIf(sys.platform == 'win32', "will not run on windows") - def test_recursive_symlink(self): - with TemporaryDirectory() as td: - cm = FileContentsManager(root_dir=td) - path = 'test recursive symlink' - _make_dir(cm, path) - os_path = cm._get_os_path(path) - os.symlink("recursive", os.path.join(os_path, "recursive")) - file_model = cm.new_untitled(path=path, ext='.txt') - - model = cm.get(path) - - contents = { - content['name']: content for content in model['content'] - } - self.assertIn('untitled.txt', contents) - self.assertEqual(contents['untitled.txt'], file_model) - # recursive symlinks should not be shown in the contents manager - self.assertNotIn('recursive', contents) - - def test_good_symlink(self): - with TemporaryDirectory() as td: - cm = FileContentsManager(root_dir=td) - parent = 'test good symlink' - name = 'good symlink' - path = '{0}/{1}'.format(parent, name) - _make_dir(cm, parent) - - file_model = cm.new(path=parent + '/zfoo.txt') - - # create a good symlink - self.symlink(cm, file_model['path'], path) - symlink_model = cm.get(path, content=False) - dir_model = cm.get(parent) - self.assertEqual( - sorted(dir_model['content'], key=lambda x: x['name']), - [symlink_model, file_model], - ) - - - @skipIf(hasattr(os, 'getuid') and os.getuid() == 0, "Can't test permissions as root") - @skipIf(sys.platform.startswith('win'), "Can't test permissions on Windows") - def test_403(self): - with TemporaryDirectory() as td: - cm = FileContentsManager(root_dir=td) - model = cm.new_untitled(type='file') - os_path = cm._get_os_path(model['path']) - - os.chmod(os_path, 0o400) - try: - with cm.open(os_path, 'w') as f: - f.write(u"don't care") - except HTTPError as e: - self.assertEqual(e.status_code, 403) - else: - self.fail("Should have raised HTTPError(403)") - - def test_escape_root(self): - with TemporaryDirectory() as td: - cm = FileContentsManager(root_dir=td) - # make foo, bar next to root - with open(os.path.join(cm.root_dir, '..', 'foo'), 'w') as f: - f.write('foo') - with open(os.path.join(cm.root_dir, '..', 'bar'), 'w') as f: - f.write('bar') - - with self.assertRaisesHTTPError(404): - cm.get('..') - with self.assertRaisesHTTPError(404): - cm.get('foo/../../../bar') - with self.assertRaisesHTTPError(404): - cm.delete('../foo') - with self.assertRaisesHTTPError(404): - cm.rename('../foo', '../bar') - with self.assertRaisesHTTPError(404): - cm.save(model={ - 'type': 'file', - 'content': u'', - 'format': 'text', - }, path='../foo') - - -class TestContentsManager(TestCase): - @contextmanager - def assertRaisesHTTPError(self, status, msg=None): - msg = msg or "Should have raised HTTPError(%i)" % status - try: - yield - except HTTPError as e: - self.assertEqual(e.status_code, status) - else: - self.fail(msg) - - def make_populated_dir(self, api_path): - cm = self.contents_manager - - self.make_dir(api_path) - - cm.new(path="/".join([api_path, "nb.ipynb"])) - cm.new(path="/".join([api_path, "file.txt"])) - - def check_populated_dir_files(self, api_path): - dir_model = self.contents_manager.get(api_path) - - self.assertEqual(dir_model['path'], api_path) - self.assertEqual(dir_model['type'], "directory") - - for entry in dir_model['content']: - if entry['type'] == "directory": - continue - elif entry['type'] == "file": - self.assertEqual(entry['name'], "file.txt") - complete_path = "/".join([api_path, "file.txt"]) - self.assertEqual(entry["path"], complete_path) - elif entry['type'] == "notebook": - self.assertEqual(entry['name'], "nb.ipynb") - complete_path = "/".join([api_path, "nb.ipynb"]) - self.assertEqual(entry["path"], complete_path) - - def setUp(self): - self._temp_dir = TemporaryDirectory() - self.td = self._temp_dir.name - self.contents_manager = FileContentsManager( - root_dir=self.td, - ) - - def tearDown(self): - self._temp_dir.cleanup() - - def make_dir(self, api_path): - """make a subdirectory at api_path - - override in subclasses if contents are not on the filesystem. - """ - _make_dir(self.contents_manager, api_path) - - def add_code_cell(self, nb): - output = nbformat.new_output("display_data", {'application/javascript': "alert('hi');"}) - cell = nbformat.new_code_cell("print('hi')", outputs=[output]) - nb.cells.append(cell) - - def new_notebook(self): - cm = self.contents_manager - model = cm.new_untitled(type='notebook') - name = model['name'] - path = model['path'] - - full_model = cm.get(path) - nb = full_model['content'] - nb['metadata']['counter'] = int(1e6 * time.time()) - self.add_code_cell(nb) - - cm.save(full_model, path) - return nb, name, path - - def test_new_untitled(self): - cm = self.contents_manager - # Test in root directory - model = cm.new_untitled(type='notebook') - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertIn('type', model) - self.assertEqual(model['type'], 'notebook') - self.assertEqual(model['name'], 'Untitled.ipynb') - self.assertEqual(model['path'], 'Untitled.ipynb') - - # Test in sub-directory - model = cm.new_untitled(type='directory') - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertIn('type', model) - self.assertEqual(model['type'], 'directory') - self.assertEqual(model['name'], 'Untitled Folder') - self.assertEqual(model['path'], 'Untitled Folder') - sub_dir = model['path'] - - model = cm.new_untitled(path=sub_dir) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertIn('type', model) - self.assertEqual(model['type'], 'file') - self.assertEqual(model['name'], 'untitled') - self.assertEqual(model['path'], '%s/untitled' % sub_dir) - - # Test with a compound extension - model = cm.new_untitled(path=sub_dir, ext='.foo.bar') - self.assertEqual(model['name'], 'untitled.foo.bar') - model = cm.new_untitled(path=sub_dir, ext='.foo.bar') - self.assertEqual(model['name'], 'untitled1.foo.bar') - - def test_modified_date(self): - - cm = self.contents_manager - - # Create a new notebook. - nb, name, path = self.new_notebook() - model = cm.get(path) - - # Add a cell and save. - self.add_code_cell(model['content']) - cm.save(model, path) - - # Reload notebook and verify that last_modified incremented. - saved = cm.get(path) - self.assertGreaterEqual(saved['last_modified'], model['last_modified']) - - # Move the notebook and verify that last_modified stayed the same. - # (The frontend fires a warning if last_modified increases on the - # renamed file.) - new_path = 'renamed.ipynb' - cm.rename(path, new_path) - renamed = cm.get(new_path) - self.assertGreaterEqual( - renamed['last_modified'], - saved['last_modified'], - ) - - def test_get(self): - cm = self.contents_manager - # Create a notebook - model = cm.new_untitled(type='notebook') - name = model['name'] - path = model['path'] - - # Check that we 'get' on the notebook we just created - model2 = cm.get(path) - assert isinstance(model2, dict) - self.assertIn('name', model2) - self.assertIn('path', model2) - self.assertEqual(model['name'], name) - self.assertEqual(model['path'], path) - - nb_as_file = cm.get(path, content=True, type='file') - self.assertEqual(nb_as_file['path'], path) - self.assertEqual(nb_as_file['type'], 'file') - self.assertEqual(nb_as_file['format'], 'text') - self.assertNotIsInstance(nb_as_file['content'], dict) - - nb_as_bin_file = cm.get(path, content=True, type='file', format='base64') - self.assertEqual(nb_as_bin_file['format'], 'base64') - - # Test in sub-directory - sub_dir = '/foo/' - self.make_dir('foo') - model = cm.new_untitled(path=sub_dir, ext='.ipynb') - model2 = cm.get(sub_dir + name) - assert isinstance(model2, dict) - self.assertIn('name', model2) - self.assertIn('path', model2) - self.assertIn('content', model2) - self.assertEqual(model2['name'], 'Untitled.ipynb') - self.assertEqual(model2['path'], '{0}/{1}'.format(sub_dir.strip('/'), name)) - - # Test with a regular file. - file_model_path = cm.new_untitled(path=sub_dir, ext='.txt')['path'] - file_model = cm.get(file_model_path) - self.assertDictContainsSubset( - { - 'content': u'', - 'format': u'text', - 'mimetype': u'text/plain', - 'name': u'untitled.txt', - 'path': u'foo/untitled.txt', - 'type': u'file', - 'writable': True, - }, - file_model, - ) - self.assertIn('created', file_model) - self.assertIn('last_modified', file_model) - - # Test getting directory model - - # Create a sub-sub directory to test getting directory contents with a - # subdir. - self.make_dir('foo/bar') - dirmodel = cm.get('foo') - self.assertEqual(dirmodel['type'], 'directory') - self.assertIsInstance(dirmodel['content'], list) - self.assertEqual(len(dirmodel['content']), 3) - self.assertEqual(dirmodel['path'], 'foo') - self.assertEqual(dirmodel['name'], 'foo') - - # Directory contents should match the contents of each individual entry - # when requested with content=False. - model2_no_content = cm.get(sub_dir + name, content=False) - file_model_no_content = cm.get(u'foo/untitled.txt', content=False) - sub_sub_dir_no_content = cm.get('foo/bar', content=False) - self.assertEqual(sub_sub_dir_no_content['path'], 'foo/bar') - self.assertEqual(sub_sub_dir_no_content['name'], 'bar') - - for entry in dirmodel['content']: - # Order isn't guaranteed by the spec, so this is a hacky way of - # verifying that all entries are matched. - if entry['path'] == sub_sub_dir_no_content['path']: - self.assertEqual(entry, sub_sub_dir_no_content) - elif entry['path'] == model2_no_content['path']: - self.assertEqual(entry, model2_no_content) - elif entry['path'] == file_model_no_content['path']: - self.assertEqual(entry, file_model_no_content) - else: - self.fail("Unexpected directory entry: %s" % entry()) - - with self.assertRaises(HTTPError): - cm.get('foo', type='file') - - def test_update(self): - cm = self.contents_manager - # Create a notebook - model = cm.new_untitled(type='notebook') - name = model['name'] - path = model['path'] - - # Change the name in the model for rename - model['path'] = 'test.ipynb' - model = cm.update(model, path) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertEqual(model['name'], 'test.ipynb') - - # Make sure the old name is gone - self.assertRaises(HTTPError, cm.get, path) - - # Test in sub-directory - # Create a directory and notebook in that directory - sub_dir = '/foo/' - self.make_dir('foo') - model = cm.new_untitled(path=sub_dir, type='notebook') - path = model['path'] - - # Change the name in the model for rename - d = path.rsplit('/', 1)[0] - new_path = model['path'] = d + '/test_in_sub.ipynb' - model = cm.update(model, path) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertEqual(model['name'], 'test_in_sub.ipynb') - self.assertEqual(model['path'], new_path) - - # Make sure the old name is gone - self.assertRaises(HTTPError, cm.get, path) - - def test_save(self): - cm = self.contents_manager - # Create a notebook - model = cm.new_untitled(type='notebook') - name = model['name'] - path = model['path'] - - # Get the model with 'content' - full_model = cm.get(path) - - # Save the notebook - model = cm.save(full_model, path) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertEqual(model['name'], name) - self.assertEqual(model['path'], path) - - # Test in sub-directory - # Create a directory and notebook in that directory - sub_dir = '/foo/' - self.make_dir('foo') - model = cm.new_untitled(path=sub_dir, type='notebook') - name = model['name'] - path = model['path'] - model = cm.get(path) - - # Change the name in the model for rename - model = cm.save(model, path) - assert isinstance(model, dict) - self.assertIn('name', model) - self.assertIn('path', model) - self.assertEqual(model['name'], 'Untitled.ipynb') - self.assertEqual(model['path'], 'foo/Untitled.ipynb') - - def test_delete(self): - cm = self.contents_manager - # Create a notebook - nb, name, path = self.new_notebook() - - # Delete the notebook - cm.delete(path) - - # Check that deleting a non-existent path raises an error. - self.assertRaises(HTTPError, cm.delete, path) - - # Check that a 'get' on the deleted notebook raises and error - self.assertRaises(HTTPError, cm.get, path) - - def test_rename(self): - cm = self.contents_manager - # Create a new notebook - nb, name, path = self.new_notebook() - - # Rename the notebook - cm.rename(path, "changed_path") - - # Attempting to get the notebook under the old name raises an error - self.assertRaises(HTTPError, cm.get, path) - # Fetching the notebook under the new name is successful - assert isinstance(cm.get("changed_path"), dict) - - # Test validation. Currently, only Windows has a non-empty set of invalid characters - if sys.platform == 'win32' and isinstance(cm, FileContentsManager): - with self.assertRaisesHTTPError(400): - cm.rename("changed_path", "prevent: in name") - - # Ported tests on nested directory renaming from pgcontents - all_dirs = ['foo', 'bar', 'foo/bar', 'foo/bar/foo', 'foo/bar/foo/bar'] - unchanged_dirs = all_dirs[:2] - changed_dirs = all_dirs[2:] - - for _dir in all_dirs: - self.make_populated_dir(_dir) - self.check_populated_dir_files(_dir) - - # Renaming to an existing directory should fail - for src, dest in combinations(all_dirs, 2): - with self.assertRaisesHTTPError(409): - cm.rename(src, dest) - - # Creating a notebook in a non_existant directory should fail - with self.assertRaisesHTTPError(404): - cm.new_untitled("foo/bar_diff", ext=".ipynb") - - cm.rename("foo/bar", "foo/bar_diff") - - # Assert that unchanged directories remain so - for unchanged in unchanged_dirs: - self.check_populated_dir_files(unchanged) - - # Assert changed directories can no longer be accessed under old names - for changed_dirname in changed_dirs: - with self.assertRaisesHTTPError(404): - cm.get(changed_dirname) - - new_dirname = changed_dirname.replace("foo/bar", "foo/bar_diff", 1) - - self.check_populated_dir_files(new_dirname) - - # Created a notebook in the renamed directory should work - cm.new_untitled("foo/bar_diff", ext=".ipynb") - - def test_delete_root(self): - cm = self.contents_manager - with self.assertRaises(HTTPError) as err: - cm.delete('') - self.assertEqual(err.exception.status_code, 400) - - def test_copy(self): - cm = self.contents_manager - parent = u'å b' - name = u'nb √.ipynb' - path = u'{0}/{1}'.format(parent, name) - self.make_dir(parent) - - orig = cm.new(path=path) - # copy with unspecified name - copy = cm.copy(path) - self.assertEqual(copy['name'], orig['name'].replace('.ipynb', '-Copy1.ipynb')) - - # copy with specified name - copy2 = cm.copy(path, u'å b/copy 2.ipynb') - self.assertEqual(copy2['name'], u'copy 2.ipynb') - self.assertEqual(copy2['path'], u'å b/copy 2.ipynb') - # copy with specified path - copy2 = cm.copy(path, u'/') - self.assertEqual(copy2['name'], name) - self.assertEqual(copy2['path'], name) - - def test_trust_notebook(self): - cm = self.contents_manager - nb, name, path = self.new_notebook() - - untrusted = cm.get(path)['content'] - assert not cm.notary.check_cells(untrusted) - - # print(untrusted) - cm.trust_notebook(path) - trusted = cm.get(path)['content'] - # print(trusted) - assert cm.notary.check_cells(trusted) - - def test_mark_trusted_cells(self): - cm = self.contents_manager - nb, name, path = self.new_notebook() - - cm.mark_trusted_cells(nb, path) - for cell in nb.cells: - if cell.cell_type == 'code': - assert not cell.metadata.trusted - - cm.trust_notebook(path) - nb = cm.get(path)['content'] - for cell in nb.cells: - if cell.cell_type == 'code': - assert cell.metadata.trusted - - def test_check_and_sign(self): - cm = self.contents_manager - nb, name, path = self.new_notebook() - - cm.mark_trusted_cells(nb, path) - cm.check_and_sign(nb, path) - assert not cm.notary.check_signature(nb) - - cm.trust_notebook(path) - nb = cm.get(path)['content'] - cm.mark_trusted_cells(nb, path) - cm.check_and_sign(nb, path) - assert cm.notary.check_signature(nb) - - -class TestContentsManagerNoAtomic(TestContentsManager): - """ - Make same test in no atomic case than in atomic case, using inheritance - """ - - def setUp(self): - self._temp_dir = TemporaryDirectory() - self.td = self._temp_dir.name - self.contents_manager = FileContentsManager( - root_dir = self.td, - ) - self.contents_manager.use_atomic_writing = False diff --git a/notebook/services/kernels/__init__.py b/notebook/services/kernels/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/kernels/handlers.py b/notebook/services/kernels/handlers.py deleted file mode 100644 index a2d4ddbab..000000000 --- a/notebook/services/kernels/handlers.py +++ /dev/null @@ -1,646 +0,0 @@ -"""Tornado handlers for kernels. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#kernels-api -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import json -import logging -from textwrap import dedent - -from tornado import gen, web -from tornado.concurrent import Future -from tornado.ioloop import IOLoop - -from jupyter_client import protocol_version as client_protocol_version -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import ( - date_default as json_default - ) -from ipython_genutils.py3compat import cast_unicode -from notebook.utils import maybe_future, url_path_join, url_escape - -from ...base.handlers import APIHandler -from ...base.zmqhandlers import AuthenticatedZMQStreamHandler, deserialize_binary_message - -class MainKernelHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self): - km = self.kernel_manager - kernels = yield maybe_future(km.list_kernels()) - self.finish(json.dumps(kernels, default=json_default)) - - @web.authenticated - @gen.coroutine - def post(self): - km = self.kernel_manager - model = self.get_json_body() - if model is None: - model = { - 'name': km.default_kernel_name - } - else: - model.setdefault('name', km.default_kernel_name) - - kernel_id = yield maybe_future(km.start_kernel(kernel_name=model['name'])) - model = yield maybe_future(km.kernel_model(kernel_id)) - location = url_path_join(self.base_url, 'api', 'kernels', url_escape(kernel_id)) - self.set_header('Location', location) - self.set_status(201) - self.finish(json.dumps(model, default=json_default)) - - -class KernelHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self, kernel_id): - km = self.kernel_manager - model = yield maybe_future(km.kernel_model(kernel_id)) - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @gen.coroutine - def delete(self, kernel_id): - km = self.kernel_manager - yield maybe_future(km.shutdown_kernel(kernel_id)) - self.set_status(204) - self.finish() - - -class KernelActionHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def post(self, kernel_id, action): - km = self.kernel_manager - if action == 'interrupt': - yield maybe_future(km.interrupt_kernel(kernel_id)) - self.set_status(204) - if action == 'restart': - - try: - yield maybe_future(km.restart_kernel(kernel_id)) - except Exception as e: - self.log.error("Exception restarting kernel", exc_info=True) - self.set_status(500) - else: - model = yield maybe_future(km.kernel_model(kernel_id)) - self.write(json.dumps(model, default=json_default)) - self.finish() - - -class ZMQChannelsHandler(AuthenticatedZMQStreamHandler): - '''There is one ZMQChannelsHandler per running kernel and it oversees all - the sessions. - ''' - - # class-level registry of open sessions - # allows checking for conflict on session-id, - # which is used as a zmq identity and must be unique. - _open_sessions = {} - - @property - def kernel_info_timeout(self): - km_default = self.kernel_manager.kernel_info_timeout - return self.settings.get('kernel_info_timeout', km_default) - - @property - def iopub_msg_rate_limit(self): - return self.settings.get('iopub_msg_rate_limit', 0) - - @property - def iopub_data_rate_limit(self): - return self.settings.get('iopub_data_rate_limit', 0) - - @property - def rate_limit_window(self): - return self.settings.get('rate_limit_window', 1.0) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, getattr(self, 'kernel_id', 'uninitialized')) - - def create_stream(self): - km = self.kernel_manager - identity = self.session.bsession - for channel in ("iopub", "shell", "control", "stdin"): - meth = getattr(km, "connect_" + channel) - self.channels[channel] = stream = meth(self.kernel_id, identity=identity) - stream.channel = channel - - def nudge(self): - """Nudge the zmq connections with kernel_info_requests - - Returns a Future that will resolve when we have received - a shell or control reply and at least one iopub message, - ensuring that zmq subscriptions are established, - sockets are fully connected, and kernel is responsive. - - Keeps retrying kernel_info_request until these are both received. - """ - kernel = self.kernel_manager.get_kernel(self.kernel_id) - - # Do not nudge busy kernels as kernel info requests sent to shell are - # queued behind execution requests. - # nudging in this case would cause a potentially very long wait - # before connections are opened, - # plus it is *very* unlikely that a busy kernel will not finish - # establishing its zmq subscriptions before processing the next request. - if getattr(kernel, "execution_state") == "busy": - self.log.debug("Nudge: not nudging busy kernel %s", self.kernel_id) - f = Future() - f.set_result(None) - return f - # Use a transient shell channel to prevent leaking - # shell responses to the front-end. - shell_channel = kernel.connect_shell() - # Use a transient control channel to prevent leaking - # control responses to the front-end. - control_channel = kernel.connect_control() - # The IOPub used by the client, whose subscriptions we are verifying. - iopub_channel = self.channels["iopub"] - - info_future = Future() - iopub_future = Future() - both_done = gen.multi([info_future, iopub_future]) - - def finish(f=None): - """Ensure all futures are resolved - - which in turn triggers cleanup - """ - for f in (info_future, iopub_future): - if not f.done(): - f.set_result(None) - - def cleanup(f=None): - """Common cleanup""" - loop.remove_timeout(nudge_handle) - iopub_channel.stop_on_recv() - if not shell_channel.closed(): - shell_channel.close() - if not control_channel.closed(): - control_channel.close() - - # trigger cleanup when both message futures are resolved - both_done.add_done_callback(cleanup) - - def on_shell_reply(msg): - self.log.debug("Nudge: shell info reply received: %s", self.kernel_id) - if not info_future.done(): - self.log.debug("Nudge: resolving shell future: %s", self.kernel_id) - info_future.set_result(None) - - def on_control_reply(msg): - self.log.debug("Nudge: control info reply received: %s", self.kernel_id) - if not info_future.done(): - self.log.debug("Nudge: resolving control future: %s", self.kernel_id) - info_future.set_result(None) - - def on_iopub(msg): - self.log.debug("Nudge: IOPub received: %s", self.kernel_id) - if not iopub_future.done(): - iopub_channel.stop_on_recv() - self.log.debug("Nudge: resolving iopub future: %s", self.kernel_id) - iopub_future.set_result(None) - - iopub_channel.on_recv(on_iopub) - shell_channel.on_recv(on_shell_reply) - control_channel.on_recv(on_control_reply) - loop = IOLoop.current() - - # Nudge the kernel with kernel info requests until we get an IOPub message - def nudge(count): - count += 1 - - # NOTE: this close check appears to never be True during on_open, - # even when the peer has closed the connection - if self.ws_connection is None or self.ws_connection.is_closing(): - self.log.debug( - "Nudge: cancelling on closed websocket: %s", self.kernel_id - ) - finish() - return - - # check for stopped kernel - if self.kernel_id not in self.kernel_manager: - self.log.debug( - "Nudge: cancelling on stopped kernel: %s", self.kernel_id - ) - finish() - return - - # check for closed zmq socket - if shell_channel.closed(): - self.log.debug("Nudge: cancelling on closed zmq socket: %s", self.kernel_id) - finish() - return - - # check for closed zmq socket - if control_channel.closed(): - self.log.debug( - "Nudge: cancelling on closed zmq socket: %s", self.kernel_id - ) - finish() - return - - if not both_done.done(): - log = self.log.warning if count % 10 == 0 else self.log.debug - log("Nudge: attempt %s on kernel %s" % (count, self.kernel_id)) - self.session.send(shell_channel, "kernel_info_request") - self.session.send(control_channel, "kernel_info_request") - nonlocal nudge_handle - nudge_handle = loop.call_later(0.5, nudge, count) - - nudge_handle = loop.call_later(0, nudge, count=0) - - # resolve with a timeout if we get no response - future = gen.with_timeout(loop.time() + self.kernel_info_timeout, both_done) - # ensure we have no dangling resources or unresolved Futures in case of timeout - future.add_done_callback(finish) - return future - - def request_kernel_info(self): - """send a request for kernel_info""" - km = self.kernel_manager - kernel = km.get_kernel(self.kernel_id) - try: - # check for previous request - future = kernel._kernel_info_future - except AttributeError: - self.log.debug("Requesting kernel info from %s", self.kernel_id) - # Create a kernel_info channel to query the kernel protocol version. - # This channel will be closed after the kernel_info reply is received. - if self.kernel_info_channel is None: - self.kernel_info_channel = km.connect_shell(self.kernel_id) - self.kernel_info_channel.on_recv(self._handle_kernel_info_reply) - self.session.send(self.kernel_info_channel, "kernel_info_request") - # store the future on the kernel, so only one request is sent - kernel._kernel_info_future = self._kernel_info_future - else: - if not future.done(): - self.log.debug("Waiting for pending kernel_info request") - future.add_done_callback(lambda f: self._finish_kernel_info(f.result())) - return self._kernel_info_future - - def _handle_kernel_info_reply(self, msg): - """process the kernel_info_reply - - enabling msg spec adaptation, if necessary - """ - idents,msg = self.session.feed_identities(msg) - try: - msg = self.session.deserialize(msg) - except: - self.log.error("Bad kernel_info reply", exc_info=True) - self._kernel_info_future.set_result({}) - return - else: - info = msg['content'] - self.log.debug("Received kernel info: %s", info) - if msg['msg_type'] != 'kernel_info_reply' or 'protocol_version' not in info: - self.log.error("Kernel info request failed, assuming current %s", info) - info = {} - self._finish_kernel_info(info) - - # close the kernel_info channel, we don't need it anymore - if self.kernel_info_channel: - self.kernel_info_channel.close() - self.kernel_info_channel = None - - def _finish_kernel_info(self, info): - """Finish handling kernel_info reply - - Set up protocol adaptation, if needed, - and signal that connection can continue. - """ - protocol_version = info.get('protocol_version', client_protocol_version) - if protocol_version != client_protocol_version: - self.session.adapt_version = int(protocol_version.split('.')[0]) - self.log.info("Adapting from protocol version {protocol_version} (kernel {kernel_id}) to {client_protocol_version} (client).".format(protocol_version=protocol_version, kernel_id=self.kernel_id, client_protocol_version=client_protocol_version)) - if not self._kernel_info_future.done(): - self._kernel_info_future.set_result(info) - - def initialize(self): - super().initialize() - self.zmq_stream = None - self.channels = {} - self.kernel_id = None - self.kernel_info_channel = None - self._kernel_info_future = Future() - self._close_future = Future() - self.session_key = '' - - # Rate limiting code - self._iopub_window_msg_count = 0 - self._iopub_window_byte_count = 0 - self._iopub_msgs_exceeded = False - self._iopub_data_exceeded = False - # Queue of (time stamp, byte count) - # Allows you to specify that the byte count should be lowered - # by a delta amount at some point in the future. - self._iopub_window_byte_queue = [] - - @gen.coroutine - def pre_get(self): - # authenticate first - super().pre_get() - # check session collision: - yield self._register_session() - # then request kernel info, waiting up to a certain time before giving up. - # We don't want to wait forever, because browsers don't take it well when - # servers never respond to websocket connection requests. - kernel = self.kernel_manager.get_kernel(self.kernel_id) - self.session.key = kernel.session.key - future = self.request_kernel_info() - - def give_up(): - """Don't wait forever for the kernel to reply""" - if future.done(): - return - self.log.warning("Timeout waiting for kernel_info reply from %s", self.kernel_id) - future.set_result({}) - loop = IOLoop.current() - loop.add_timeout(loop.time() + self.kernel_info_timeout, give_up) - # actually wait for it - yield future - - @gen.coroutine - def get(self, kernel_id): - self.kernel_id = cast_unicode(kernel_id, 'ascii') - yield super().get(kernel_id=kernel_id) - - @gen.coroutine - def _register_session(self): - """Ensure we aren't creating a duplicate session. - - If a previous identical session is still open, close it to avoid collisions. - This is likely due to a client reconnecting from a lost network connection, - where the socket on our side has not been cleaned up yet. - """ - self.session_key = '%s:%s' % (self.kernel_id, self.session.session) - stale_handler = self._open_sessions.get(self.session_key) - if stale_handler: - self.log.warning("Replacing stale connection: %s", self.session_key) - yield stale_handler.close() - if self.kernel_id in self.kernel_manager: # only update open sessions if kernel is actively managed - self._open_sessions[self.session_key] = self - - def open(self, kernel_id): - super().open() - km = self.kernel_manager - km.notify_connect(kernel_id) - - # on new connections, flush the message buffer - buffer_info = km.get_buffer(kernel_id, self.session_key) - if buffer_info and buffer_info['session_key'] == self.session_key: - self.log.info("Restoring connection for %s", self.session_key) - self.channels = buffer_info['channels'] - connected = self.nudge() - - def replay(value): - replay_buffer = buffer_info['buffer'] - if replay_buffer: - self.log.info("Replaying %s buffered messages", len(replay_buffer)) - for channel, msg_list in replay_buffer: - stream = self.channels[channel] - self._on_zmq_reply(stream, msg_list) - - connected.add_done_callback(replay) - else: - try: - self.create_stream() - connected = self.nudge() - except web.HTTPError as e: - self.log.error("Error opening stream: %s", e) - # WebSockets don't response to traditional error codes so we - # close the connection. - for channel, stream in self.channels.items(): - if not stream.closed(): - stream.close() - self.close() - return - - km.add_restart_callback(self.kernel_id, self.on_kernel_restarted) - km.add_restart_callback(self.kernel_id, self.on_restart_failed, 'dead') - - def subscribe(value): - for channel, stream in self.channels.items(): - stream.on_recv_stream(self._on_zmq_reply) - - connected.add_done_callback(subscribe) - - return connected - - def on_message(self, msg): - if not self.channels: - # already closed, ignore the message - self.log.debug("Received message on closed websocket %r", msg) - return - if isinstance(msg, bytes): - msg = deserialize_binary_message(msg) - else: - msg = json.loads(msg) - channel = msg.pop('channel', None) - if channel is None: - self.log.warning("No channel specified, assuming shell: %s", msg) - channel = 'shell' - if channel not in self.channels: - self.log.warning("No such channel: %r", channel) - return - am = self.kernel_manager.allowed_message_types - mt = msg['header']['msg_type'] - if am and mt not in am: - self.log.warning('Received message of type "%s", which is not allowed. Ignoring.' % mt) - else: - stream = self.channels[channel] - self.session.send(stream, msg) - - def _on_zmq_reply(self, stream, msg_list): - idents, fed_msg_list = self.session.feed_identities(msg_list) - msg = self.session.deserialize(fed_msg_list) - parent = msg['parent_header'] - def write_stderr(error_message): - self.log.warning(error_message) - msg = self.session.msg("stream", - content={"text": error_message + '\n', "name": "stderr"}, - parent=parent - ) - msg['channel'] = 'iopub' - self.write_message(json.dumps(msg, default=json_default)) - channel = getattr(stream, 'channel', None) - msg_type = msg['header']['msg_type'] - - if channel == 'iopub' and msg_type == 'status' and msg['content'].get('execution_state') == 'idle': - # reset rate limit counter on status=idle, - # to avoid 'Run All' hitting limits prematurely. - self._iopub_window_byte_queue = [] - self._iopub_window_msg_count = 0 - self._iopub_window_byte_count = 0 - self._iopub_msgs_exceeded = False - self._iopub_data_exceeded = False - - if channel == 'iopub' and msg_type not in {'status', 'comm_open', 'execute_input'}: - - # Remove the counts queued for removal. - now = IOLoop.current().time() - while len(self._iopub_window_byte_queue) > 0: - queued = self._iopub_window_byte_queue[0] - if (now >= queued[0]): - self._iopub_window_byte_count -= queued[1] - self._iopub_window_msg_count -= 1 - del self._iopub_window_byte_queue[0] - else: - # This part of the queue hasn't be reached yet, so we can - # abort the loop. - break - - # Increment the bytes and message count - self._iopub_window_msg_count += 1 - if msg_type == 'stream': - byte_count = sum([len(x) for x in msg_list]) - else: - byte_count = 0 - self._iopub_window_byte_count += byte_count - - # Queue a removal of the byte and message count for a time in the - # future, when we are no longer interested in it. - self._iopub_window_byte_queue.append((now + self.rate_limit_window, byte_count)) - - # Check the limits, set the limit flags, and reset the - # message and data counts. - msg_rate = float(self._iopub_window_msg_count) / self.rate_limit_window - data_rate = float(self._iopub_window_byte_count) / self.rate_limit_window - - # Check the msg rate - if self.iopub_msg_rate_limit > 0 and msg_rate > self.iopub_msg_rate_limit: - if not self._iopub_msgs_exceeded: - self._iopub_msgs_exceeded = True - write_stderr(dedent("""\ - IOPub message rate exceeded. - The notebook server will temporarily stop sending output - to the client in order to avoid crashing it. - To change this limit, set the config variable - `--NotebookApp.iopub_msg_rate_limit`. - - Current values: - NotebookApp.iopub_msg_rate_limit={} (msgs/sec) - NotebookApp.rate_limit_window={} (secs) - """.format(self.iopub_msg_rate_limit, self.rate_limit_window))) - else: - # resume once we've got some headroom below the limit - if self._iopub_msgs_exceeded and msg_rate < (0.8 * self.iopub_msg_rate_limit): - self._iopub_msgs_exceeded = False - if not self._iopub_data_exceeded: - self.log.warning("iopub messages resumed") - - # Check the data rate - if self.iopub_data_rate_limit > 0 and data_rate > self.iopub_data_rate_limit: - if not self._iopub_data_exceeded: - self._iopub_data_exceeded = True - write_stderr(dedent("""\ - IOPub data rate exceeded. - The notebook server will temporarily stop sending output - to the client in order to avoid crashing it. - To change this limit, set the config variable - `--NotebookApp.iopub_data_rate_limit`. - - Current values: - NotebookApp.iopub_data_rate_limit={} (bytes/sec) - NotebookApp.rate_limit_window={} (secs) - """.format(self.iopub_data_rate_limit, self.rate_limit_window))) - else: - # resume once we've got some headroom below the limit - if self._iopub_data_exceeded and data_rate < (0.8 * self.iopub_data_rate_limit): - self._iopub_data_exceeded = False - if not self._iopub_msgs_exceeded: - self.log.warning("iopub messages resumed") - - # If either of the limit flags are set, do not send the message. - if self._iopub_msgs_exceeded or self._iopub_data_exceeded: - # we didn't send it, remove the current message from the calculus - self._iopub_window_msg_count -= 1 - self._iopub_window_byte_count -= byte_count - self._iopub_window_byte_queue.pop(-1) - return - super()._on_zmq_reply(stream, msg) - - def close(self): - super().close() - return self._close_future - - def on_close(self): - self.log.debug("Websocket closed %s", self.session_key) - # unregister myself as an open session (only if it's really me) - if self._open_sessions.get(self.session_key) is self: - self._open_sessions.pop(self.session_key) - - km = self.kernel_manager - if self.kernel_id in km: - km.notify_disconnect(self.kernel_id) - km.remove_restart_callback( - self.kernel_id, self.on_kernel_restarted, - ) - km.remove_restart_callback( - self.kernel_id, self.on_restart_failed, 'dead', - ) - - # start buffering instead of closing if this was the last connection - if km._kernel_connections[self.kernel_id] == 0: - km.start_buffering(self.kernel_id, self.session_key, self.channels) - self._close_future.set_result(None) - return - - # This method can be called twice, once by self.kernel_died and once - # from the WebSocket close event. If the WebSocket connection is - # closed before the ZMQ streams are setup, they could be None. - for channel, stream in self.channels.items(): - if stream is not None and not stream.closed(): - stream.on_recv(None) - stream.close() - - self.channels = {} - self._close_future.set_result(None) - - def _send_status_message(self, status): - iopub = self.channels.get('iopub', None) - if iopub and not iopub.closed(): - # flush IOPub before sending a restarting/dead status message - # ensures proper ordering on the IOPub channel - # that all messages from the stopped kernel have been delivered - iopub.flush() - msg = self.session.msg("status", - {'execution_state': status} - ) - msg['channel'] = 'iopub' - self.write_message(json.dumps(msg, default=json_default)) - - def on_kernel_restarted(self): - logging.warn("kernel %s restarted", self.kernel_id) - self._send_status_message('restarting') - - def on_restart_failed(self): - logging.error("kernel %s restarted failed!", self.kernel_id) - self._send_status_message('dead') - - -#----------------------------------------------------------------------------- -# URL to handler mappings -#----------------------------------------------------------------------------- - - -_kernel_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" -_kernel_action_regex = r"(?Prestart|interrupt)" - -default_handlers = [ - (r"/api/kernels", MainKernelHandler), - (r"/api/kernels/%s" % _kernel_id_regex, KernelHandler), - (r"/api/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler), - (r"/api/kernels/%s/channels" % _kernel_id_regex, ZMQChannelsHandler), -] diff --git a/notebook/services/kernels/kernelmanager.py b/notebook/services/kernels/kernelmanager.py deleted file mode 100644 index 7ed182dfc..000000000 --- a/notebook/services/kernels/kernelmanager.py +++ /dev/null @@ -1,520 +0,0 @@ -"""A MultiKernelManager for use in the notebook webserver -- raises HTTPErrors -- creates REST API models -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from collections import defaultdict -from datetime import datetime, timedelta -from functools import partial -import os - -from tornado import web -from tornado.concurrent import Future -from tornado.ioloop import IOLoop, PeriodicCallback - -from jupyter_client.session import Session -from jupyter_client.multikernelmanager import MultiKernelManager -from traitlets import (Any, Bool, Dict, List, Unicode, TraitError, Integer, - Float, Instance, default, validate -) - -from notebook.utils import maybe_future, to_os_path, exists -from notebook._tz import utcnow, isoformat -from ipython_genutils.py3compat import getcwd - -from notebook.prometheus.metrics import KERNEL_CURRENTLY_RUNNING_TOTAL - -# Since use of AsyncMultiKernelManager is optional at the moment, don't require appropriate jupyter_client. -# This will be confirmed at runtime in notebookapp. The following block can be removed once the jupyter_client's -# floor has been updated. -try: - from jupyter_client.multikernelmanager import AsyncMultiKernelManager -except ImportError: - class AsyncMultiKernelManager(object): - """Empty class to satisfy unused reference by AsyncMappingKernelManager.""" - def __init__(self, **kwargs): - pass - - -class MappingKernelManager(MultiKernelManager): - """A KernelManager that handles notebook mapping and HTTP error handling""" - - @default('kernel_manager_class') - def _default_kernel_manager_class(self): - return "jupyter_client.ioloop.IOLoopKernelManager" - - kernel_argv = List(Unicode()) - - root_dir = Unicode(config=True) - - _kernel_connections = Dict() - - _culler_callback = None - - _initialized_culler = False - - @default('root_dir') - def _default_root_dir(self): - try: - return self.parent.notebook_dir - except AttributeError: - return getcwd() - - @validate('root_dir') - def _update_root_dir(self, proposal): - """Do a bit of validation of the root dir.""" - value = proposal['value'] - if not os.path.isabs(value): - # If we receive a non-absolute path, make it absolute. - value = os.path.abspath(value) - if not exists(value) or not os.path.isdir(value): - raise TraitError("kernel root dir %r is not a directory" % value) - return value - - cull_idle_timeout = Integer(0, config=True, - help="""Timeout (in seconds) after which a kernel is considered idle and ready to be culled. - Values of 0 or lower disable culling. Very short timeouts may result in kernels being culled - for users with poor network connections.""" - ) - - cull_interval_default = 300 # 5 minutes - cull_interval = Integer(cull_interval_default, config=True, - help="""The interval (in seconds) on which to check for idle kernels exceeding the cull timeout value.""" - ) - - cull_connected = Bool(False, config=True, - help="""Whether to consider culling kernels which have one or more connections. - Only effective if cull_idle_timeout > 0.""" - ) - - cull_busy = Bool(False, config=True, - help="""Whether to consider culling kernels which are busy. - Only effective if cull_idle_timeout > 0.""" - ) - - buffer_offline_messages = Bool(True, config=True, - help="""Whether messages from kernels whose frontends have disconnected should be buffered in-memory. - When True (default), messages are buffered and replayed on reconnect, - avoiding lost messages due to interrupted connectivity. - Disable if long-running kernels will produce too much output while - no frontends are connected. - """ - ) - - kernel_info_timeout = Float(60, config=True, - help="""Timeout for giving up on a kernel (in seconds). - On starting and restarting kernels, we check whether the - kernel is running and responsive by sending kernel_info_requests. - This sets the timeout in seconds for how long the kernel can take - before being presumed dead. - This affects the MappingKernelManager (which handles kernel restarts) - and the ZMQChannelsHandler (which handles the startup). - """ - ) - - _kernel_buffers = Any() - @default('_kernel_buffers') - def _default_kernel_buffers(self): - return defaultdict(lambda: {'buffer': [], 'session_key': '', 'channels': {}}) - - last_kernel_activity = Instance(datetime, - help="The last activity on any kernel, including shutting down a kernel") - - allowed_message_types = List(trait=Unicode(), config=True, - help="""White list of allowed kernel message types. - When the list is empty, all message types are allowed. - """ - ) - - #------------------------------------------------------------------------- - # Methods for managing kernels and sessions - #------------------------------------------------------------------------- - - def __init__(self, **kwargs): - # Pin the superclass to better control the MRO. This is needed by - # AsyncMappingKernelManager so that it can give priority to methods - # on AsyncMultiKernelManager over this superclass. - self.pinned_superclass = MultiKernelManager - self.pinned_superclass.__init__(self, **kwargs) - self.last_kernel_activity = utcnow() - - def _handle_kernel_died(self, kernel_id): - """notice that a kernel died""" - self.log.warning("Kernel %s died, removing from map.", kernel_id) - self.remove_kernel(kernel_id) - - def cwd_for_path(self, path): - """Turn API path into absolute OS path.""" - os_path = to_os_path(path, self.root_dir) - # in the case of notebooks and kernels not being on the same filesystem, - # walk up to root_dir if the paths don't exist - while not os.path.isdir(os_path) and os_path != self.root_dir: - os_path = os.path.dirname(os_path) - return os_path - - async def start_kernel(self, kernel_id=None, path=None, **kwargs): - """Start a kernel for a session and return its kernel_id. - Parameters - ---------- - kernel_id : uuid - The uuid to associate the new kernel with. If this - is not None, this kernel will be persistent whenever it is - requested. - path : API path - The API path (unicode, '/' delimited) for the cwd. - Will be transformed to an OS path relative to root_dir. - kernel_name : str - The name identifying which kernel spec to launch. This is ignored if - an existing kernel is returned, but it may be checked in the future. - """ - if kernel_id is None: - if path is not None: - kwargs['cwd'] = self.cwd_for_path(path) - kernel_id = await maybe_future(self.pinned_superclass.start_kernel(self, **kwargs)) - self._kernel_connections[kernel_id] = 0 - self.start_watching_activity(kernel_id) - self.log.info("Kernel started: %s, name: %s" % (kernel_id, self._kernels[kernel_id].kernel_name)) - self.log.debug("Kernel args: %r" % kwargs) - # register callback for failed auto-restart - self.add_restart_callback(kernel_id, - lambda : self._handle_kernel_died(kernel_id), - 'dead', - ) - - # Increase the metric of number of kernels running - # for the relevant kernel type by 1 - KERNEL_CURRENTLY_RUNNING_TOTAL.labels( - type=self._kernels[kernel_id].kernel_name - ).inc() - - else: - self._check_kernel_id(kernel_id) - self.log.info("Using existing kernel: %s" % kernel_id) - - # Initialize culling if not already - if not self._initialized_culler: - self.initialize_culler() - - return kernel_id - - def start_buffering(self, kernel_id, session_key, channels): - """Start buffering messages for a kernel - Parameters - ---------- - kernel_id : str - The id of the kernel to start buffering. - session_key: str - The session_key, if any, that should get the buffer. - If the session_key matches the current buffered session_key, - the buffer will be returned. - channels: dict({'channel': ZMQStream}) - The zmq channels whose messages should be buffered. - """ - - if not self.buffer_offline_messages: - for channel, stream in channels.items(): - stream.close() - return - - self.log.info("Starting buffering for %s", session_key) - self._check_kernel_id(kernel_id) - # clear previous buffering state - self.stop_buffering(kernel_id) - buffer_info = self._kernel_buffers[kernel_id] - # record the session key because only one session can buffer - buffer_info['session_key'] = session_key - # TODO: the buffer should likely be a memory bounded queue, we're starting with a list to keep it simple - buffer_info['buffer'] = [] - buffer_info['channels'] = channels - - # forward any future messages to the internal buffer - def buffer_msg(channel, msg_parts): - self.log.debug("Buffering msg on %s:%s", kernel_id, channel) - buffer_info['buffer'].append((channel, msg_parts)) - - for channel, stream in channels.items(): - stream.on_recv(partial(buffer_msg, channel)) - - def get_buffer(self, kernel_id, session_key): - """Get the buffer for a given kernel - Parameters - ---------- - kernel_id : str - The id of the kernel to stop buffering. - session_key: str, optional - The session_key, if any, that should get the buffer. - If the session_key matches the current buffered session_key, - the buffer will be returned. - """ - self.log.debug("Getting buffer for %s", kernel_id) - if kernel_id not in self._kernel_buffers: - return - - buffer_info = self._kernel_buffers[kernel_id] - if buffer_info['session_key'] == session_key: - # remove buffer - self._kernel_buffers.pop(kernel_id) - # only return buffer_info if it's a match - return buffer_info - else: - self.stop_buffering(kernel_id) - - def stop_buffering(self, kernel_id): - """Stop buffering kernel messages - Parameters - ---------- - kernel_id : str - The id of the kernel to stop buffering. - """ - self.log.debug("Clearing buffer for %s", kernel_id) - self._check_kernel_id(kernel_id) - - if kernel_id not in self._kernel_buffers: - return - buffer_info = self._kernel_buffers.pop(kernel_id) - # close buffering streams - for stream in buffer_info['channels'].values(): - if not stream.closed(): - stream.on_recv(None) - stream.close() - - msg_buffer = buffer_info['buffer'] - if msg_buffer: - self.log.info("Discarding %s buffered messages for %s", - len(msg_buffer), buffer_info['session_key']) - - def shutdown_kernel(self, kernel_id, now=False, restart=False): - """Shutdown a kernel by kernel_id""" - self._check_kernel_id(kernel_id) - kernel = self._kernels[kernel_id] - if kernel._activity_stream: - kernel._activity_stream.close() - kernel._activity_stream = None - self.stop_buffering(kernel_id) - - # Decrease the metric of number of kernels - # running for the relevant kernel type by 1 - KERNEL_CURRENTLY_RUNNING_TOTAL.labels( - type=self._kernels[kernel_id].kernel_name - ).dec() - - self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart) - # Unlike its async sibling method in AsyncMappingKernelManager, removing the kernel_id - # from the connections dictionary isn't as problematic before the shutdown since the - # method is synchronous. However, we'll keep the relative call orders the same from - # a maintenance perspective. - self._kernel_connections.pop(kernel_id, None) - - async def restart_kernel(self, kernel_id, now=False): - """Restart a kernel by kernel_id""" - self._check_kernel_id(kernel_id) - await maybe_future(self.pinned_superclass.restart_kernel(self, kernel_id, now=now)) - kernel = self.get_kernel(kernel_id) - # return a Future that will resolve when the kernel has successfully restarted - channel = kernel.connect_shell() - future = Future() - - def finish(): - """Common cleanup when restart finishes/fails for any reason.""" - if not channel.closed(): - channel.close() - loop.remove_timeout(timeout) - kernel.remove_restart_callback(on_restart_failed, 'dead') - - def on_reply(msg): - self.log.debug("Kernel info reply received: %s", kernel_id) - finish() - if not future.done(): - future.set_result(msg) - - def on_timeout(): - self.log.warning("Timeout waiting for kernel_info_reply: %s", kernel_id) - finish() - if not future.done(): - future.set_exception(TimeoutError("Timeout waiting for restart")) - - def on_restart_failed(): - self.log.warning("Restarting kernel failed: %s", kernel_id) - finish() - if not future.done(): - future.set_exception(RuntimeError("Restart failed")) - - kernel.add_restart_callback(on_restart_failed, 'dead') - kernel.session.send(channel, "kernel_info_request") - channel.on_recv(on_reply) - loop = IOLoop.current() - timeout = loop.add_timeout(loop.time() + self.kernel_info_timeout, on_timeout) - return future - - def notify_connect(self, kernel_id): - """Notice a new connection to a kernel""" - if kernel_id in self._kernel_connections: - self._kernel_connections[kernel_id] += 1 - - def notify_disconnect(self, kernel_id): - """Notice a disconnection from a kernel""" - if kernel_id in self._kernel_connections: - self._kernel_connections[kernel_id] -= 1 - - def kernel_model(self, kernel_id): - """Return a JSON-safe dict representing a kernel - For use in representing kernels in the JSON APIs. - """ - self._check_kernel_id(kernel_id) - kernel = self._kernels[kernel_id] - - model = { - "id": kernel_id, - "name": kernel.kernel_name, - "last_activity": isoformat(kernel.last_activity), - "execution_state": kernel.execution_state, - "connections": self._kernel_connections[kernel_id], - } - return model - - def list_kernels(self): - """Returns a list of kernel_id's of kernels running.""" - kernels = [] - kernel_ids = self.pinned_superclass.list_kernel_ids(self) - for kernel_id in kernel_ids: - try: - model = self.kernel_model(kernel_id) - kernels.append(model) - except (web.HTTPError, KeyError): - pass # Probably due to a (now) non-existent kernel, continue building the list - return kernels - - # override _check_kernel_id to raise 404 instead of KeyError - def _check_kernel_id(self, kernel_id): - """Check a that a kernel_id exists and raise 404 if not.""" - if kernel_id not in self: - raise web.HTTPError(404, u'Kernel does not exist: %s' % kernel_id) - - # monitoring activity: - - def start_watching_activity(self, kernel_id): - """Start watching IOPub messages on a kernel for activity. - - update last_activity on every message - - record execution_state from status messages - """ - kernel = self._kernels[kernel_id] - # add busy/activity markers: - kernel.execution_state = 'starting' - kernel.last_activity = utcnow() - kernel._activity_stream = kernel.connect_iopub() - session = Session( - config=kernel.session.config, - key=kernel.session.key, - ) - - def record_activity(msg_list): - """Record an IOPub message arriving from a kernel""" - self.last_kernel_activity = kernel.last_activity = utcnow() - - idents, fed_msg_list = session.feed_identities(msg_list) - msg = session.deserialize(fed_msg_list) - - msg_type = msg['header']['msg_type'] - if msg_type == 'status': - kernel.execution_state = msg['content']['execution_state'] - self.log.debug("activity on %s: %s (%s)", kernel_id, msg_type, kernel.execution_state) - else: - self.log.debug("activity on %s: %s", kernel_id, msg_type) - - kernel._activity_stream.on_recv(record_activity) - - def initialize_culler(self): - """Start idle culler if 'cull_idle_timeout' is greater than zero. - Regardless of that value, set flag that we've been here. - """ - if not self._initialized_culler and self.cull_idle_timeout > 0: - if self._culler_callback is None: - loop = IOLoop.current() - if self.cull_interval <= 0: # handle case where user set invalid value - self.log.warning("Invalid value for 'cull_interval' detected (%s) - using default value (%s).", - self.cull_interval, self.cull_interval_default) - self.cull_interval = self.cull_interval_default - self._culler_callback = PeriodicCallback( - self.cull_kernels, 1000*self.cull_interval) - self.log.info("Culling kernels with idle durations > %s seconds at %s second intervals ...", - self.cull_idle_timeout, self.cull_interval) - if self.cull_busy: - self.log.info("Culling kernels even if busy") - if self.cull_connected: - self.log.info("Culling kernels even with connected clients") - self._culler_callback.start() - - self._initialized_culler = True - - async def cull_kernels(self): - self.log.debug("Polling every %s seconds for kernels idle > %s seconds...", - self.cull_interval, self.cull_idle_timeout) - """Create a separate list of kernels to avoid conflicting updates while iterating""" - for kernel_id in list(self._kernels): - try: - await self.cull_kernel_if_idle(kernel_id) - except Exception as e: - self.log.exception("The following exception was encountered while checking the " - "idle duration of kernel {}: {}".format(kernel_id, e)) - - async def cull_kernel_if_idle(self, kernel_id): - try: - kernel = self._kernels[kernel_id] - except KeyError: - return # KeyErrors are somewhat expected since the kernel can be shutdown as the culling check is made. - - if hasattr(kernel, 'last_activity'): # last_activity is monkey-patched, so ensure that has occurred - self.log.debug("kernel_id=%s, kernel_name=%s, last_activity=%s", - kernel_id, kernel.kernel_name, kernel.last_activity) - dt_now = utcnow() - dt_idle = dt_now - kernel.last_activity - # Compute idle properties - is_idle_time = dt_idle > timedelta(seconds=self.cull_idle_timeout) - is_idle_execute = self.cull_busy or (kernel.execution_state != 'busy') - connections = self._kernel_connections.get(kernel_id, 0) - is_idle_connected = self.cull_connected or not connections - # Cull the kernel if all three criteria are met - if (is_idle_time and is_idle_execute and is_idle_connected): - idle_duration = int(dt_idle.total_seconds()) - self.log.warning("Culling '%s' kernel '%s' (%s) with %d connections due to %s seconds of inactivity.", - kernel.execution_state, kernel.kernel_name, kernel_id, connections, idle_duration) - await maybe_future(self.shutdown_kernel(kernel_id)) - - -# AsyncMappingKernelManager inherits as much as possible from MappingKernelManager, overriding -# only what is different. -class AsyncMappingKernelManager(MappingKernelManager, AsyncMultiKernelManager): - @default('kernel_manager_class') - def _default_kernel_manager_class(self): - return "jupyter_client.ioloop.AsyncIOLoopKernelManager" - - def __init__(self, **kwargs): - # Pin the superclass to better control the MRO. - self.pinned_superclass = AsyncMultiKernelManager - self.pinned_superclass.__init__(self, **kwargs) - self.last_kernel_activity = utcnow() - - async def shutdown_kernel(self, kernel_id, now=False, restart=False): - """Shutdown a kernel by kernel_id""" - self._check_kernel_id(kernel_id) - kernel = self._kernels[kernel_id] - if kernel._activity_stream: - kernel._activity_stream.close() - kernel._activity_stream = None - self.stop_buffering(kernel_id) - - # Decrease the metric of number of kernels - # running for the relevant kernel type by 1 - KERNEL_CURRENTLY_RUNNING_TOTAL.labels( - type=self._kernels[kernel_id].kernel_name - ).dec() - - await self.pinned_superclass.shutdown_kernel(self, kernel_id, now=now, restart=restart) - # Remove kernel_id from the connections dictionary only after kernel has been shutdown, - # otherwise a race condition can occur since the shutdown may take a while - allowing - # list/fetch kernel operations to access _kernel_connections for a non-existent key - # (kernel_id) while "awaiting" the result of the shutdown. - self._kernel_connections.pop(kernel_id, None) diff --git a/notebook/services/kernels/tests/__init__.py b/notebook/services/kernels/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/kernels/tests/test_kernels_api.py b/notebook/services/kernels/tests/test_kernels_api.py deleted file mode 100644 index 7895f36a8..000000000 --- a/notebook/services/kernels/tests/test_kernels_api.py +++ /dev/null @@ -1,286 +0,0 @@ -"""Test the kernels service API.""" - -import json -import sys -import time - -from requests import HTTPError -from traitlets.config import Config - -from tornado.httpclient import HTTPRequest -from tornado.ioloop import IOLoop -from tornado.websocket import websocket_connect -from unittest import SkipTest - -from jupyter_client.kernelspec import NATIVE_KERNEL_NAME - -from notebook.utils import url_path_join -from notebook.tests.launchnotebook import NotebookTestBase, assert_http_error - -try: - from jupyter_client import AsyncMultiKernelManager - async_testing_enabled = True -except ImportError: - async_testing_enabled = False - - -class KernelAPI(object): - """Wrapper for kernel REST API requests""" - def __init__(self, request, base_url, headers): - self.request = request - self.base_url = base_url - self.headers = headers - - def _req(self, verb, path, body=None): - response = self.request(verb, - url_path_join('api/kernels', path), data=body) - - if 400 <= response.status_code < 600: - try: - response.reason = response.json()['message'] - except: - pass - response.raise_for_status() - - return response - - def list(self): - return self._req('GET', '') - - def get(self, id): - return self._req('GET', id) - - def start(self, name=NATIVE_KERNEL_NAME): - body = json.dumps({'name': name}) - return self._req('POST', '', body) - - def shutdown(self, id): - return self._req('DELETE', id) - - def interrupt(self, id): - return self._req('POST', url_path_join(id, 'interrupt')) - - def restart(self, id): - return self._req('POST', url_path_join(id, 'restart')) - - def websocket(self, id): - loop = IOLoop() - loop.make_current() - req = HTTPRequest( - url_path_join(self.base_url.replace('http', 'ws', 1), 'api/kernels', id, 'channels'), - headers=self.headers, - ) - f = websocket_connect(req) - return loop.run_sync(lambda : f) - - -class KernelAPITest(NotebookTestBase): - """Test the kernels web service API""" - def setUp(self): - self.kern_api = KernelAPI(self.request, - base_url=self.base_url(), - headers=self.auth_headers(), - ) - - def tearDown(self): - for k in self.kern_api.list().json(): - self.kern_api.shutdown(k['id']) - - def test_no_kernels(self): - """Make sure there are no kernels running at the start""" - kernels = self.kern_api.list().json() - self.assertEqual(kernels, []) - - def test_default_kernel(self): - # POST request - r = self.kern_api._req('POST', '') - kern1 = r.json() - self.assertEqual(r.headers['location'], url_path_join(self.url_prefix, 'api/kernels', kern1['id'])) - self.assertEqual(r.status_code, 201) - self.assertIsInstance(kern1, dict) - - report_uri = url_path_join(self.url_prefix, 'api/security/csp-report') - expected_csp = '; '.join([ - "frame-ancestors 'self'", - 'report-uri ' + report_uri, - "default-src 'none'" - ]) - self.assertEqual(r.headers['Content-Security-Policy'], expected_csp) - - def test_main_kernel_handler(self): - # POST request - r = self.kern_api.start() - kern1 = r.json() - self.assertEqual(r.headers['location'], url_path_join(self.url_prefix, 'api/kernels', kern1['id'])) - self.assertEqual(r.status_code, 201) - self.assertIsInstance(kern1, dict) - - report_uri = url_path_join(self.url_prefix, 'api/security/csp-report') - expected_csp = '; '.join([ - "frame-ancestors 'self'", - 'report-uri ' + report_uri, - "default-src 'none'" - ]) - self.assertEqual(r.headers['Content-Security-Policy'], expected_csp) - - # GET request - r = self.kern_api.list() - self.assertEqual(r.status_code, 200) - assert isinstance(r.json(), list) - self.assertEqual(r.json()[0]['id'], kern1['id']) - self.assertEqual(r.json()[0]['name'], kern1['name']) - - # create another kernel and check that they both are added to the - # list of kernels from a GET request - kern2 = self.kern_api.start().json() - assert isinstance(kern2, dict) - r = self.kern_api.list() - kernels = r.json() - self.assertEqual(r.status_code, 200) - assert isinstance(kernels, list) - self.assertEqual(len(kernels), 2) - - # Interrupt a kernel - r = self.kern_api.interrupt(kern2['id']) - self.assertEqual(r.status_code, 204) - - # Restart a kernel - r = self.kern_api.restart(kern2['id']) - rekern = r.json() - self.assertEqual(rekern['id'], kern2['id']) - self.assertEqual(rekern['name'], kern2['name']) - - def test_kernel_handler(self): - # GET kernel with given id - kid = self.kern_api.start().json()['id'] - r = self.kern_api.get(kid) - kern1 = r.json() - self.assertEqual(r.status_code, 200) - assert isinstance(kern1, dict) - self.assertIn('id', kern1) - self.assertEqual(kern1['id'], kid) - - # Request a bad kernel id and check that a JSON - # message is returned! - bad_id = '111-111-111-111-111' - with assert_http_error(404, 'Kernel does not exist: ' + bad_id): - self.kern_api.get(bad_id) - - # DELETE kernel with id - r = self.kern_api.shutdown(kid) - self.assertEqual(r.status_code, 204) - kernels = self.kern_api.list().json() - self.assertEqual(kernels, []) - - # Request to delete a non-existent kernel id - bad_id = '111-111-111-111-111' - with assert_http_error(404, 'Kernel does not exist: ' + bad_id): - self.kern_api.shutdown(bad_id) - - def test_connections(self): - kid = self.kern_api.start().json()['id'] - model = self.kern_api.get(kid).json() - self.assertEqual(model['connections'], 0) - - ws = self.kern_api.websocket(kid) - model = self.kern_api.get(kid).json() - self.assertEqual(model['connections'], 1) - ws.close() - # give it some time to close on the other side: - for i in range(10): - model = self.kern_api.get(kid).json() - if model['connections'] > 0: - time.sleep(0.1) - else: - break - model = self.kern_api.get(kid).json() - self.assertEqual(model['connections'], 0) - - -class AsyncKernelAPITest(KernelAPITest): - """Test the kernels web service API using the AsyncMappingKernelManager""" - - @classmethod - def setup_class(cls): - if not async_testing_enabled: # Can be removed once jupyter_client >= 6.1 is required. - raise SkipTest("AsyncKernelAPITest tests skipped due to down-level jupyter_client!") - super(AsyncKernelAPITest, cls).setup_class() - - @classmethod - def get_argv(cls): - argv = super(AsyncKernelAPITest, cls).get_argv() - - # before we extend the argv with the class, ensure that appropriate jupyter_client is available. - # if not available, don't set kernel_manager_class, resulting in the repeat of sync-based tests. - if async_testing_enabled: - argv.extend(['--NotebookApp.kernel_manager_class=' - 'notebook.services.kernels.kernelmanager.AsyncMappingKernelManager']) - return argv - - -class KernelFilterTest(NotebookTestBase): - - # A special install of NotebookTestBase where only `kernel_info_request` - # messages are allowed. - config = Config({ - 'NotebookApp': { - 'MappingKernelManager': { - 'allowed_message_types': ['kernel_info_request'] - } - } - }) - - # Sanity check verifying that the configurable was properly set. - def test_config(self): - self.assertEqual(self.notebook.kernel_manager.allowed_message_types, ['kernel_info_request']) - - -CULL_TIMEOUT = 5 -CULL_INTERVAL = 1 - - -class KernelCullingTest(NotebookTestBase): - """Test kernel culling """ - - @classmethod - def get_argv(cls): - argv = super(KernelCullingTest, cls).get_argv() - - # Enable culling with 5s timeout and 1s intervals - argv.extend(['--MappingKernelManager.cull_idle_timeout={}'.format(CULL_TIMEOUT), - '--MappingKernelManager.cull_interval={}'.format(CULL_INTERVAL), - '--MappingKernelManager.cull_connected=False']) - return argv - - def setUp(self): - self.kern_api = KernelAPI(self.request, - base_url=self.base_url(), - headers=self.auth_headers(), - ) - - def tearDown(self): - for k in self.kern_api.list().json(): - self.kern_api.shutdown(k['id']) - - def test_culling(self): - kid = self.kern_api.start().json()['id'] - ws = self.kern_api.websocket(kid) - model = self.kern_api.get(kid).json() - self.assertEqual(model['connections'], 1) - assert not self.get_cull_status(kid) # connected, should not be culled - ws.close() - assert self.get_cull_status(kid) # not connected, should be culled - - def get_cull_status(self, kid): - frequency = 0.5 - culled = False - for _ in range(int((CULL_TIMEOUT + CULL_INTERVAL)/frequency)): # Timeout + Interval will ensure cull - try: - self.kern_api.get(kid) - except HTTPError as e: - assert e.response.status_code == 404 - culled = True - break - else: - time.sleep(frequency) - return culled diff --git a/notebook/services/kernelspecs/__init__.py b/notebook/services/kernelspecs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/kernelspecs/handlers.py b/notebook/services/kernelspecs/handlers.py deleted file mode 100644 index a01d307fb..000000000 --- a/notebook/services/kernelspecs/handlers.py +++ /dev/null @@ -1,106 +0,0 @@ -"""Tornado handlers for kernel specifications. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-25%3A-Registry-of-installed-kernels#rest-api -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import glob -import json -import os -pjoin = os.path.join - -from tornado import web, gen - -from ...base.handlers import APIHandler -from ...utils import maybe_future, url_path_join, url_unescape - - - -def kernelspec_model(handler, name, spec_dict, resource_dir): - """Load a KernelSpec by name and return the REST API model""" - d = { - 'name': name, - 'spec': spec_dict, - 'resources': {} - } - - # Add resource files if they exist - for resource in ['kernel.js', 'kernel.css']: - if os.path.exists(pjoin(resource_dir, resource)): - d['resources'][resource] = url_path_join( - handler.base_url, - 'kernelspecs', - name, - resource - ) - for logo_file in glob.glob(pjoin(resource_dir, 'logo-*')): - fname = os.path.basename(logo_file) - no_ext, _ = os.path.splitext(fname) - d['resources'][no_ext] = url_path_join( - handler.base_url, - 'kernelspecs', - name, - fname - ) - return d - - -def is_kernelspec_model(spec_dict): - """Returns True if spec_dict is already in proper form. This will occur when using a gateway.""" - return isinstance(spec_dict, dict) and 'name' in spec_dict and 'spec' in spec_dict and 'resources' in spec_dict - - -class MainKernelSpecHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self): - ksm = self.kernel_spec_manager - km = self.kernel_manager - model = {} - model['default'] = km.default_kernel_name - model['kernelspecs'] = specs = {} - kspecs = yield maybe_future(ksm.get_all_specs()) - for kernel_name, kernel_info in kspecs.items(): - try: - if is_kernelspec_model(kernel_info): - d = kernel_info - else: - d = kernelspec_model(self, kernel_name, kernel_info['spec'], kernel_info['resource_dir']) - except Exception: - self.log.error("Failed to load kernel spec: '%s'", kernel_name, exc_info=True) - continue - specs[kernel_name] = d - self.set_header("Content-Type", 'application/json') - self.finish(json.dumps(model)) - - -class KernelSpecHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self, kernel_name): - ksm = self.kernel_spec_manager - kernel_name = url_unescape(kernel_name) - try: - spec = yield maybe_future(ksm.get_kernel_spec(kernel_name)) - except KeyError as e: - raise web.HTTPError(404, u'Kernel spec %s not found' % kernel_name) from e - if is_kernelspec_model(spec): - model = spec - else: - model = kernelspec_model(self, kernel_name, spec.to_dict(), spec.resource_dir) - self.set_header("Content-Type", 'application/json') - self.finish(json.dumps(model)) - - -# URL to handler mappings - -kernel_name_regex = r"(?P[\w\.\-%]+)" - -default_handlers = [ - (r"/api/kernelspecs", MainKernelSpecHandler), - (r"/api/kernelspecs/%s" % kernel_name_regex, KernelSpecHandler), -] diff --git a/notebook/services/kernelspecs/tests/__init__.py b/notebook/services/kernelspecs/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/kernelspecs/tests/test_kernelspecs_api.py b/notebook/services/kernelspecs/tests/test_kernelspecs_api.py deleted file mode 100644 index 215bfc861..000000000 --- a/notebook/services/kernelspecs/tests/test_kernelspecs_api.py +++ /dev/null @@ -1,136 +0,0 @@ -"""Test the kernel specs webservice API.""" - -import errno -import io -import json -import os -import shutil - -pjoin = os.path.join - -import requests - -from jupyter_client.kernelspec import NATIVE_KERNEL_NAME -from notebook.utils import url_path_join, url_escape -from notebook.tests.launchnotebook import NotebookTestBase, assert_http_error - -# Copied from jupyter_client.tests.test_kernelspec so updating that doesn't -# break these tests -sample_kernel_json = {'argv':['cat', '{connection_file}'], - 'display_name':'Test kernel', - } - -some_resource = u"The very model of a modern major general" - - -class KernelSpecAPI(object): - """Wrapper for notebook API calls.""" - def __init__(self, request): - self.request = request - - def _req(self, verb, path, body=None): - response = self.request(verb, - path, - data=body, - ) - response.raise_for_status() - return response - - def list(self): - return self._req('GET', 'api/kernelspecs') - - def kernel_spec_info(self, name): - return self._req('GET', url_path_join('api/kernelspecs', name)) - - def kernel_resource(self, name, path): - return self._req('GET', url_path_join('kernelspecs', name, path)) - - -class APITest(NotebookTestBase): - """Test the kernelspec web service API""" - def setUp(self): - self.create_spec('sample') - self.create_spec('sample 2') - self.ks_api = KernelSpecAPI(self.request) - - def create_spec(self, name): - sample_kernel_dir = pjoin(self.data_dir, 'kernels', name) - try: - os.makedirs(sample_kernel_dir) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - with open(pjoin(sample_kernel_dir, 'kernel.json'), 'w') as f: - json.dump(sample_kernel_json, f) - - with io.open(pjoin(sample_kernel_dir, 'resource.txt'), 'w', - encoding='utf-8') as f: - f.write(some_resource) - - def test_list_kernelspecs_bad(self): - """Can list kernelspecs when one is invalid""" - bad_kernel_dir = pjoin(self.data_dir, 'kernels', 'bad') - try: - os.makedirs(bad_kernel_dir) - except OSError as e: - if e.errno != errno.EEXIST: - raise - - with open(pjoin(bad_kernel_dir, 'kernel.json'), 'w') as f: - f.write("garbage") - - model = self.ks_api.list().json() - assert isinstance(model, dict) - self.assertEqual(model['default'], NATIVE_KERNEL_NAME) - specs = model['kernelspecs'] - assert isinstance(specs, dict) - # 2: the sample kernelspec created in setUp, and the native Python kernel - self.assertGreaterEqual(len(specs), 2) - - shutil.rmtree(bad_kernel_dir) - - def test_list_kernelspecs(self): - model = self.ks_api.list().json() - assert isinstance(model, dict) - self.assertEqual(model['default'], NATIVE_KERNEL_NAME) - specs = model['kernelspecs'] - assert isinstance(specs, dict) - - # 2: the sample kernelspec created in setUp, and the native Python kernel - self.assertGreaterEqual(len(specs), 2) - - def is_sample_kernelspec(s): - return s['name'] == 'sample' and s['spec']['display_name'] == 'Test kernel' - - def is_default_kernelspec(s): - return s['name'] == NATIVE_KERNEL_NAME and s['spec']['display_name'].startswith("Python") - - assert any(is_sample_kernelspec(s) for s in specs.values()), specs - assert any(is_default_kernelspec(s) for s in specs.values()), specs - - def test_get_kernelspec(self): - model = self.ks_api.kernel_spec_info('Sample').json() # Case insensitive - self.assertEqual(model['name'].lower(), 'sample') - self.assertIsInstance(model['spec'], dict) - self.assertEqual(model['spec']['display_name'], 'Test kernel') - self.assertIsInstance(model['resources'], dict) - - def test_get_kernelspec_spaces(self): - model = self.ks_api.kernel_spec_info('sample%202').json() - self.assertEqual(model['name'].lower(), 'sample 2') - - def test_get_nonexistant_kernelspec(self): - with assert_http_error(404): - self.ks_api.kernel_spec_info('nonexistant') - - def test_get_kernel_resource_file(self): - res = self.ks_api.kernel_resource('sAmple', 'resource.txt') - self.assertEqual(res.text, some_resource) - - def test_get_nonexistant_resource(self): - with assert_http_error(404): - self.ks_api.kernel_resource('nonexistant', 'resource.txt') - - with assert_http_error(404): - self.ks_api.kernel_resource('sample', 'nonexistant.txt') diff --git a/notebook/services/nbconvert/__init__.py b/notebook/services/nbconvert/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/nbconvert/handlers.py b/notebook/services/nbconvert/handlers.py deleted file mode 100644 index 7c65ee0fd..000000000 --- a/notebook/services/nbconvert/handlers.py +++ /dev/null @@ -1,39 +0,0 @@ -import json - -from tornado import web - -from ...base.handlers import APIHandler - - -class NbconvertRootHandler(APIHandler): - - @web.authenticated - def get(self): - self.check_xsrf_cookie() - try: - from nbconvert.exporters import base - except ImportError as e: - raise web.HTTPError(500, "Could not import nbconvert: %s" % e) from e - res = {} - exporters = base.get_export_names() - for exporter_name in exporters: - try: - exporter_class = base.get_exporter(exporter_name) - except ValueError: - # I think the only way this will happen is if the entrypoint - # is uninstalled while this method is running - continue - # XXX: According to the docs, it looks like this should be set to None - # if the exporter shouldn't be exposed to the front-end and a friendly - # name if it should. However, none of the built-in exports have it defined. - # if not exporter_class.export_from_notebook: - # continue - res[exporter_name] = { - "output_mimetype": exporter_class.output_mimetype, - } - - self.finish(json.dumps(res)) - -default_handlers = [ - (r"/api/nbconvert", NbconvertRootHandler), -] diff --git a/notebook/services/nbconvert/tests/__init__.py b/notebook/services/nbconvert/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/nbconvert/tests/test_nbconvert_api.py b/notebook/services/nbconvert/tests/test_nbconvert_api.py deleted file mode 100644 index d6ef9d2ca..000000000 --- a/notebook/services/nbconvert/tests/test_nbconvert_api.py +++ /dev/null @@ -1,31 +0,0 @@ -import requests - -from notebook.utils import url_path_join -from notebook.tests.launchnotebook import NotebookTestBase - -class NbconvertAPI(object): - """Wrapper for nbconvert API calls.""" - def __init__(self, request): - self.request = request - - def _req(self, verb, path, body=None, params=None): - response = self.request(verb, - url_path_join('api/nbconvert', path), - data=body, params=params, - ) - response.raise_for_status() - return response - - def list_formats(self): - return self._req('GET', '') - -class APITest(NotebookTestBase): - def setUp(self): - self.nbconvert_api = NbconvertAPI(self.request) - - def test_list_formats(self): - formats = self.nbconvert_api.list_formats().json() - self.assertIsInstance(formats, dict) - self.assertIn('python', formats) - self.assertIn('html', formats) - self.assertEqual(formats['python']['output_mimetype'], 'text/x-python') \ No newline at end of file diff --git a/notebook/services/security/__init__.py b/notebook/services/security/__init__.py deleted file mode 100644 index 9cf0d476b..000000000 --- a/notebook/services/security/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# URI for the CSP Report. Included here to prevent a cyclic dependency. -# csp_report_uri is needed both by the BaseHandler (for setting the report-uri) -# and by the CSPReportHandler (which depends on the BaseHandler). -csp_report_uri = r"/api/security/csp-report" diff --git a/notebook/services/security/handlers.py b/notebook/services/security/handlers.py deleted file mode 100644 index 82a00d234..000000000 --- a/notebook/services/security/handlers.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Tornado handlers for security logging.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -from tornado import web - -from ...base.handlers import APIHandler -from . import csp_report_uri - -class CSPReportHandler(APIHandler): - '''Accepts a content security policy violation report''' - - _track_activity = False - - def skip_check_origin(self): - """Don't check origin when reporting origin-check violations!""" - return True - - def check_xsrf_cookie(self): - # don't check XSRF for CSP reports - return - - @web.authenticated - def post(self): - '''Log a content security policy violation report''' - self.log.warning("Content security violation: %s", - self.request.body.decode('utf8', 'replace')) - -default_handlers = [ - (csp_report_uri, CSPReportHandler) -] diff --git a/notebook/services/sessions/__init__.py b/notebook/services/sessions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/sessions/handlers.py b/notebook/services/sessions/handlers.py deleted file mode 100644 index fc4b3d1d3..000000000 --- a/notebook/services/sessions/handlers.py +++ /dev/null @@ -1,180 +0,0 @@ -"""Tornado handlers for the sessions web service. - -Preliminary documentation at https://github.com/ipython/ipython/wiki/IPEP-16%3A-Notebook-multi-directory-dashboard-and-URL-mapping#sessions-api -""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import json - -from tornado import gen, web - -from ...base.handlers import APIHandler -try: - from jupyter_client.jsonutil import json_default -except ImportError: - from jupyter_client.jsonutil import ( - date_default as json_default - ) -from notebook.utils import maybe_future, url_path_join -from jupyter_client.kernelspec import NoSuchKernel - - -class SessionRootHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self): - # Return a list of running sessions - sm = self.session_manager - sessions = yield maybe_future(sm.list_sessions()) - self.finish(json.dumps(sessions, default=json_default)) - - @web.authenticated - @gen.coroutine - def post(self): - # Creates a new session - #(unless a session already exists for the named session) - sm = self.session_manager - - model = self.get_json_body() - if model is None: - raise web.HTTPError(400, "No JSON data provided") - - if 'notebook' in model and 'path' in model['notebook']: - self.log.warning('Sessions API changed, see updated swagger docs') - model['path'] = model['notebook']['path'] - model['type'] = 'notebook' - - try: - path = model['path'] - except KeyError as e: - raise web.HTTPError(400, "Missing field in JSON data: path") from e - - try: - mtype = model['type'] - except KeyError as e: - raise web.HTTPError(400, "Missing field in JSON data: type") from e - - name = model.get('name', None) - kernel = model.get('kernel', {}) - kernel_name = kernel.get('name', None) - kernel_id = kernel.get('id', None) - - if not kernel_id and not kernel_name: - self.log.debug("No kernel specified, using default kernel") - kernel_name = None - - exists = yield maybe_future(sm.session_exists(path=path)) - if exists: - model = yield maybe_future(sm.get_session(path=path)) - else: - try: - model = yield maybe_future( - sm.create_session(path=path, kernel_name=kernel_name, - kernel_id=kernel_id, name=name, - type=mtype)) - except NoSuchKernel: - msg = ("The '%s' kernel is not available. Please pick another " - "suitable kernel instead, or install that kernel." % kernel_name) - status_msg = '%s not found' % kernel_name - self.log.warning('Kernel not found: %s' % kernel_name) - self.set_status(501) - self.finish(json.dumps(dict(message=msg, short_message=status_msg))) - return - - location = url_path_join(self.base_url, 'api', 'sessions', model['id']) - self.set_header('Location', location) - self.set_status(201) - self.finish(json.dumps(model, default=json_default)) - - -class SessionHandler(APIHandler): - - @web.authenticated - @gen.coroutine - def get(self, session_id): - # Returns the JSON model for a single session - sm = self.session_manager - model = yield maybe_future(sm.get_session(session_id=session_id)) - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @gen.coroutine - def patch(self, session_id): - """Patch updates sessions: - - - path updates session to track renamed paths - - kernel.name starts a new kernel with a given kernelspec - """ - sm = self.session_manager - km = self.kernel_manager - model = self.get_json_body() - if model is None: - raise web.HTTPError(400, "No JSON data provided") - - # get the previous session model - before = yield maybe_future(sm.get_session(session_id=session_id)) - - changes = {} - if 'notebook' in model and 'path' in model['notebook']: - self.log.warning('Sessions API changed, see updated swagger docs') - model['path'] = model['notebook']['path'] - model['type'] = 'notebook' - if 'path' in model: - changes['path'] = model['path'] - if 'name' in model: - changes['name'] = model['name'] - if 'type' in model: - changes['type'] = model['type'] - if 'kernel' in model: - # Kernel id takes precedence over name. - if model['kernel'].get('id') is not None: - kernel_id = model['kernel']['id'] - if kernel_id not in km: - raise web.HTTPError(400, "No such kernel: %s" % kernel_id) - changes['kernel_id'] = kernel_id - elif model['kernel'].get('name') is not None: - kernel_name = model['kernel']['name'] - kernel_id = yield sm.start_kernel_for_session( - session_id, kernel_name=kernel_name, name=before['name'], - path=before['path'], type=before['type']) - changes['kernel_id'] = kernel_id - - yield maybe_future(sm.update_session(session_id, **changes)) - model = yield maybe_future(sm.get_session(session_id=session_id)) - - if model['kernel']['id'] != before['kernel']['id']: - # kernel_id changed because we got a new kernel - # shutdown the old one - yield maybe_future( - km.shutdown_kernel(before['kernel']['id']) - ) - self.finish(json.dumps(model, default=json_default)) - - @web.authenticated - @gen.coroutine - def delete(self, session_id): - # Deletes the session with given session_id - sm = self.session_manager - try: - yield maybe_future(sm.delete_session(session_id)) - except KeyError as e: - # the kernel was deleted but the session wasn't! - raise web.HTTPError(410, "Kernel deleted before session") from e - self.set_status(204) - self.finish() - - -#----------------------------------------------------------------------------- -# URL to handler mappings -#----------------------------------------------------------------------------- - -_session_id_regex = r"(?P\w+-\w+-\w+-\w+-\w+)" - -default_handlers = [ - (r"/api/sessions/%s" % _session_id_regex, SessionHandler), - (r"/api/sessions", SessionRootHandler) -] - diff --git a/notebook/services/sessions/sessionmanager.py b/notebook/services/sessions/sessionmanager.py deleted file mode 100644 index 568633286..000000000 --- a/notebook/services/sessions/sessionmanager.py +++ /dev/null @@ -1,288 +0,0 @@ -"""A base class session manager.""" - -# Copyright (c) Jupyter Development Team. -# Distributed under the terms of the Modified BSD License. - -import uuid - -try: - import sqlite3 -except ImportError: - # fallback on pysqlite2 if Python was build without sqlite - from pysqlite2 import dbapi2 as sqlite3 - -from tornado import gen, web - -from traitlets.config.configurable import LoggingConfigurable -from ipython_genutils.py3compat import unicode_type -from traitlets import Instance - -from notebook.utils import maybe_future -from notebook.traittypes import InstanceFromClasses - -class SessionManager(LoggingConfigurable): - - kernel_manager = Instance('notebook.services.kernels.kernelmanager.MappingKernelManager') - contents_manager = InstanceFromClasses( - klasses=[ - 'notebook.services.contents.manager.ContentsManager', - # To make custom ContentsManagers both forward+backward - # compatible, we'll relax the strictness of this trait - # and allow jupyter_server contents managers to pass - # through. If jupyter_server is not installed, this class - # will be ignored. - 'jupyter_server.services.contents.manager.ContentsManager' - ] - ) - - # Session database initialized below - _cursor = None - _connection = None - _columns = {'session_id', 'path', 'name', 'type', 'kernel_id'} - - @property - def cursor(self): - """Start a cursor and create a database called 'session'""" - if self._cursor is None: - self._cursor = self.connection.cursor() - self._cursor.execute("""CREATE TABLE session - (session_id, path, name, type, kernel_id)""") - return self._cursor - - @property - def connection(self): - """Start a database connection""" - if self._connection is None: - self._connection = sqlite3.connect(':memory:') - self._connection.row_factory = sqlite3.Row - return self._connection - - def close(self): - """Close the sqlite connection""" - if self._cursor is not None: - self._cursor.close() - self._cursor = None - - def __del__(self): - """Close connection once SessionManager closes""" - self.close() - - @gen.coroutine - def session_exists(self, path): - """Check to see if the session of a given name exists""" - exists = False - self.cursor.execute("SELECT * FROM session WHERE path=?", (path,)) - row = self.cursor.fetchone() - if row is not None: - # Note, although we found a row for the session, the associated kernel may have - # been culled or died unexpectedly. If that's the case, we should delete the - # row, thereby terminating the session. This can be done via a call to - # row_to_model that tolerates that condition. If row_to_model returns None, - # we'll return false, since, at that point, the session doesn't exist anyway. - model = yield maybe_future(self.row_to_model(row, tolerate_culled=True)) - if model is not None: - exists = True - raise gen.Return(exists) - - def new_session_id(self): - "Create a uuid for a new session" - return unicode_type(uuid.uuid4()) - - @gen.coroutine - def create_session(self, path=None, name=None, type=None, kernel_name=None, kernel_id=None): - """Creates a session and returns its model""" - session_id = self.new_session_id() - if kernel_id is not None and kernel_id in self.kernel_manager: - pass - else: - kernel_id = yield self.start_kernel_for_session(session_id, path, name, type, kernel_name) - result = yield maybe_future( - self.save_session(session_id, path=path, name=name, type=type, kernel_id=kernel_id) - ) - # py2-compat - raise gen.Return(result) - - @gen.coroutine - def start_kernel_for_session(self, session_id, path, name, type, kernel_name): - """Start a new kernel for a given session.""" - # allow contents manager to specify kernels cwd - kernel_path = self.contents_manager.get_kernel_path(path=path) - kernel_id = yield maybe_future( - self.kernel_manager.start_kernel(path=kernel_path, kernel_name=kernel_name) - ) - # py2-compat - raise gen.Return(kernel_id) - - @gen.coroutine - def save_session(self, session_id, path=None, name=None, type=None, kernel_id=None): - """Saves the items for the session with the given session_id - - Given a session_id (and any other of the arguments), this method - creates a row in the sqlite session database that holds the information - for a session. - - Parameters - ---------- - session_id : str - uuid for the session; this method must be given a session_id - path : str - the path for the given session - name: str - the name of the session - type: string - the type of the session - kernel_id : str - a uuid for the kernel associated with this session - - Returns - ------- - model : dict - a dictionary of the session model - """ - self.cursor.execute("INSERT INTO session VALUES (?,?,?,?,?)", - (session_id, path, name, type, kernel_id) - ) - result = yield maybe_future(self.get_session(session_id=session_id)) - raise gen.Return(result) - - @gen.coroutine - def get_session(self, **kwargs): - """Returns the model for a particular session. - - Takes a keyword argument and searches for the value in the session - database, then returns the rest of the session's info. - - Parameters - ---------- - **kwargs : keyword argument - must be given one of the keywords and values from the session database - (i.e. session_id, path, name, type, kernel_id) - - Returns - ------- - model : dict - returns a dictionary that includes all the information from the - session described by the kwarg. - """ - if not kwargs: - raise TypeError("must specify a column to query") - - conditions = [] - for column in kwargs.keys(): - if column not in self._columns: - raise TypeError("No such column: %r", column) - conditions.append("%s=?" % column) - - query = "SELECT * FROM session WHERE %s" % (' AND '.join(conditions)) - - self.cursor.execute(query, list(kwargs.values())) - try: - row = self.cursor.fetchone() - except KeyError: - # The kernel is missing, so the session just got deleted. - row = None - - if row is None: - q = [] - for key, value in kwargs.items(): - q.append("%s=%r" % (key, value)) - - raise web.HTTPError(404, u'Session not found: %s' % (', '.join(q))) - - try: - model = yield maybe_future(self.row_to_model(row)) - except KeyError as e: - raise web.HTTPError(404, u'Session not found: %s' % str(e)) - raise gen.Return(model) - - @gen.coroutine - def update_session(self, session_id, **kwargs): - """Updates the values in the session database. - - Changes the values of the session with the given session_id - with the values from the keyword arguments. - - Parameters - ---------- - session_id : str - a uuid that identifies a session in the sqlite3 database - **kwargs : str - the key must correspond to a column title in session database, - and the value replaces the current value in the session - with session_id. - """ - yield maybe_future(self.get_session(session_id=session_id)) - - if not kwargs: - # no changes - return - - sets = [] - for column in kwargs.keys(): - if column not in self._columns: - raise TypeError("No such column: %r" % column) - sets.append("%s=?" % column) - query = "UPDATE session SET %s WHERE session_id=?" % (', '.join(sets)) - self.cursor.execute(query, list(kwargs.values()) + [session_id]) - - def kernel_culled(self, kernel_id): - """Checks if the kernel is still considered alive and returns true if its not found. """ - return kernel_id not in self.kernel_manager - - @gen.coroutine - def row_to_model(self, row, tolerate_culled=False): - """Takes sqlite database session row and turns it into a dictionary""" - kernel_culled = yield maybe_future(self.kernel_culled(row['kernel_id'])) - if kernel_culled: - # The kernel was culled or died without deleting the session. - # We can't use delete_session here because that tries to find - # and shut down the kernel - so we'll delete the row directly. - # - # If caller wishes to tolerate culled kernels, log a warning - # and return None. Otherwise, raise KeyError with a similar - # message. - self.cursor.execute("DELETE FROM session WHERE session_id=?", - (row['session_id'],)) - msg = "Kernel '{kernel_id}' appears to have been culled or died unexpectedly, " \ - "invalidating session '{session_id}'. The session has been removed.".\ - format(kernel_id=row['kernel_id'],session_id=row['session_id']) - if tolerate_culled: - self.log.warning(msg + " Continuing...") - raise gen.Return(None) - raise KeyError(msg) - - kernel_model = yield maybe_future(self.kernel_manager.kernel_model(row['kernel_id'])) - model = { - 'id': row['session_id'], - 'path': row['path'], - 'name': row['name'], - 'type': row['type'], - 'kernel': kernel_model - } - if row['type'] == 'notebook': - # Provide the deprecated API. - model['notebook'] = {'path': row['path'], 'name': row['name']} - raise gen.Return(model) - - @gen.coroutine - def list_sessions(self): - """Returns a list of dictionaries containing all the information from - the session database""" - c = self.cursor.execute("SELECT * FROM session") - result = [] - # We need to use fetchall() here, because row_to_model can delete rows, - # which messes up the cursor if we're iterating over rows. - for row in c.fetchall(): - try: - model = yield maybe_future(self.row_to_model(row)) - result.append(model) - except KeyError: - pass - raise gen.Return(result) - - @gen.coroutine - def delete_session(self, session_id): - """Deletes the row in the session database with given session_id""" - session = yield maybe_future(self.get_session(session_id=session_id)) - yield maybe_future(self.kernel_manager.shutdown_kernel(session['kernel']['id'])) - self.cursor.execute("DELETE FROM session WHERE session_id=?", (session_id,)) diff --git a/notebook/services/sessions/tests/__init__.py b/notebook/services/sessions/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/notebook/services/sessions/tests/test_sessionmanager.py b/notebook/services/sessions/tests/test_sessionmanager.py deleted file mode 100644 index 9af38033c..000000000 --- a/notebook/services/sessions/tests/test_sessionmanager.py +++ /dev/null @@ -1,256 +0,0 @@ -"""Tests for the session manager.""" - -from functools import partial -from unittest import TestCase - -from tornado import gen, web -from tornado.ioloop import IOLoop - -from ..sessionmanager import SessionManager -from notebook.services.kernels.kernelmanager import MappingKernelManager -from notebook.services.contents.manager import ContentsManager -from notebook._tz import utcnow, isoformat - -class DummyKernel(object): - def __init__(self, kernel_name='python'): - self.kernel_name = kernel_name - -dummy_date = utcnow() -dummy_date_s = isoformat(dummy_date) - -class DummyMKM(MappingKernelManager): - """MappingKernelManager interface that doesn't start kernels, for testing""" - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.id_letters = iter(u'ABCDEFGHIJK') - - def _new_id(self): - return next(self.id_letters) - - def start_kernel(self, kernel_id=None, path=None, kernel_name='python', **kwargs): - kernel_id = kernel_id or self._new_id() - k = self._kernels[kernel_id] = DummyKernel(kernel_name=kernel_name) - self._kernel_connections[kernel_id] = 0 - k.last_activity = dummy_date - k.execution_state = 'idle' - return kernel_id - - def shutdown_kernel(self, kernel_id, now=False): - del self._kernels[kernel_id] - - -class TestSessionManager(TestCase): - - def setUp(self): - self.sm = SessionManager( - kernel_manager=DummyMKM(), - contents_manager=ContentsManager(), - ) - self.loop = IOLoop() - self.addCleanup(partial(self.loop.close, all_fds=True)) - - def create_sessions(self, *kwarg_list): - @gen.coroutine - def co_add(): - sessions = [] - for kwargs in kwarg_list: - kwargs.setdefault('type', 'notebook') - session = yield self.sm.create_session(**kwargs) - sessions.append(session) - raise gen.Return(sessions) - return self.loop.run_sync(co_add) - - def create_session(self, **kwargs): - return self.create_sessions(kwargs)[0] - - def test_get_session(self): - sm = self.sm - session_id = self.create_session(path='/path/to/test.ipynb', kernel_name='bar')['id'] - model = self.loop.run_sync(lambda: sm.get_session(session_id=session_id)) - expected = {'id':session_id, - 'path': u'/path/to/test.ipynb', - 'notebook': {'path': u'/path/to/test.ipynb', 'name': None}, - 'type': 'notebook', - 'name': None, - 'kernel': { - 'id': 'A', - 'name': 'bar', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - }} - self.assertEqual(model, expected) - - def test_bad_get_session(self): - # Should raise error if a bad key is passed to the database. - sm = self.sm - session_id = self.create_session(path='/path/to/test.ipynb', - kernel_name='foo')['id'] - with self.assertRaises(TypeError): - self.loop.run_sync(lambda: sm.get_session(bad_id=session_id)) # Bad keyword - - def test_get_session_dead_kernel(self): - sm = self.sm - session = self.create_session(path='/path/to/1/test1.ipynb', kernel_name='python') - # kill the kernel - sm.kernel_manager.shutdown_kernel(session['kernel']['id']) - with self.assertRaises(web.HTTPError): - self.loop.run_sync(lambda: sm.get_session(session_id=session['id'])) - # no sessions left - listed = self.loop.run_sync(lambda: sm.list_sessions()) - self.assertEqual(listed, []) - - def test_list_sessions(self): - sm = self.sm - sessions = self.create_sessions( - dict(path='/path/to/1/test1.ipynb', kernel_name='python'), - dict(path='/path/to/2/test2.py', type='file', kernel_name='python'), - dict(path='/path/to/3', name='foo', type='console', kernel_name='python'), - ) - - sessions = self.loop.run_sync(lambda: sm.list_sessions()) - expected = [ - { - 'id':sessions[0]['id'], - 'path': u'/path/to/1/test1.ipynb', - 'type': 'notebook', - 'notebook': {'path': u'/path/to/1/test1.ipynb', 'name': None}, - 'name': None, - 'kernel': { - 'id': 'A', - 'name':'python', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - }, { - 'id':sessions[1]['id'], - 'path': u'/path/to/2/test2.py', - 'type': 'file', - 'name': None, - 'kernel': { - 'id': 'B', - 'name':'python', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - }, { - 'id':sessions[2]['id'], - 'path': u'/path/to/3', - 'type': 'console', - 'name': 'foo', - 'kernel': { - 'id': 'C', - 'name':'python', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - } - ] - self.assertEqual(sessions, expected) - - def test_list_sessions_dead_kernel(self): - sm = self.sm - sessions = self.create_sessions( - dict(path='/path/to/1/test1.ipynb', kernel_name='python'), - dict(path='/path/to/2/test2.ipynb', kernel_name='python'), - ) - # kill one of the kernels - sm.kernel_manager.shutdown_kernel(sessions[0]['kernel']['id']) - listed = self.loop.run_sync(lambda: sm.list_sessions()) - expected = [ - { - 'id': sessions[1]['id'], - 'path': u'/path/to/2/test2.ipynb', - 'type': 'notebook', - 'name': None, - 'notebook': {'path': u'/path/to/2/test2.ipynb', 'name': None}, - 'kernel': { - 'id': 'B', - 'name':'python', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - } - ] - self.assertEqual(listed, expected) - - def test_update_session(self): - sm = self.sm - session_id = self.create_session(path='/path/to/test.ipynb', - kernel_name='julia')['id'] - self.loop.run_sync(lambda: sm.update_session(session_id, path='/path/to/new_name.ipynb')) - model = self.loop.run_sync(lambda: sm.get_session(session_id=session_id)) - expected = {'id':session_id, - 'path': u'/path/to/new_name.ipynb', - 'type': 'notebook', - 'name': None, - 'notebook': {'path': u'/path/to/new_name.ipynb', 'name': None}, - 'kernel': { - 'id': 'A', - 'name':'julia', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - } - self.assertEqual(model, expected) - - def test_bad_update_session(self): - # try to update a session with a bad keyword ~ raise error - sm = self.sm - session_id = self.create_session(path='/path/to/test.ipynb', - kernel_name='ir')['id'] - with self.assertRaises(TypeError): - self.loop.run_sync(lambda: sm.update_session(session_id=session_id, bad_kw='test.ipynb')) # Bad keyword - - def test_delete_session(self): - sm = self.sm - sessions = self.create_sessions( - dict(path='/path/to/1/test1.ipynb', kernel_name='python'), - dict(path='/path/to/2/test2.ipynb', kernel_name='python'), - dict(path='/path/to/3', name='foo', type='console', kernel_name='python'), - ) - self.loop.run_sync(lambda: sm.delete_session(sessions[1]['id'])) - new_sessions = self.loop.run_sync(lambda: sm.list_sessions()) - expected = [{ - 'id': sessions[0]['id'], - 'path': u'/path/to/1/test1.ipynb', - 'type': 'notebook', - 'name': None, - 'notebook': {'path': u'/path/to/1/test1.ipynb', 'name': None}, - 'kernel': { - 'id': 'A', - 'name':'python', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - }, { - 'id': sessions[2]['id'], - 'type': 'console', - 'path': u'/path/to/3', - 'name': 'foo', - 'kernel': { - 'id': 'C', - 'name':'python', - 'connections': 0, - 'last_activity': dummy_date_s, - 'execution_state': 'idle', - } - } - ] - self.assertEqual(new_sessions, expected) - - def test_bad_delete_session(self): - # try to delete a session that doesn't exist ~ raise error - sm = self.sm - self.create_session(path='/path/to/test.ipynb', kernel_name='python') - with self.assertRaises(TypeError): - self.loop.run_sync(lambda : sm.delete_session(bad_kwarg='23424')) # Bad keyword - with self.assertRaises(web.HTTPError): - self.loop.run_sync(lambda : sm.delete_session(session_id='23424')) # nonexistent - diff --git a/notebook/services/sessions/tests/test_sessions_api.py b/notebook/services/sessions/tests/test_sessions_api.py deleted file mode 100644 index cb4bc0bde..000000000 --- a/notebook/services/sessions/tests/test_sessions_api.py +++ /dev/null @@ -1,288 +0,0 @@ -"""Test the sessions web service API.""" - -import errno -from functools import partial -import io -import os -import json -import shutil -import sys -import time - -from unittest import SkipTest - -from notebook.utils import url_path_join -from notebook.tests.launchnotebook import NotebookTestBase, assert_http_error -from nbformat.v4 import new_notebook -from nbformat import write - -try: - from jupyter_client import AsyncMultiKernelManager - async_testing_enabled = True -except ImportError: - async_testing_enabled = False - -pjoin = os.path.join - - -class SessionAPI(object): - """Wrapper for notebook API calls.""" - def __init__(self, request): - self.request = request - - def _req(self, verb, path, body=None): - response = self.request(verb, - url_path_join('api/sessions', path), data=body) - - if 400 <= response.status_code < 600: - try: - response.reason = response.json()['message'] - except: - pass - response.raise_for_status() - - return response - - def list(self): - return self._req('GET', '') - - def get(self, id): - return self._req('GET', id) - - def create(self, path, type='notebook', kernel_name='python', kernel_id=None): - body = json.dumps({'path': path, - 'type': type, - 'kernel': {'name': kernel_name, - 'id': kernel_id}}) - return self._req('POST', '', body) - - def create_deprecated(self, path): - body = json.dumps({'notebook': {'path': path}, - 'kernel': {'name': 'python', - 'id': 'foo'}}) - return self._req('POST', '', body) - - def modify_path(self, id, path): - body = json.dumps({'path': path}) - return self._req('PATCH', id, body) - - def modify_path_deprecated(self, id, path): - body = json.dumps({'notebook': {'path': path}}) - return self._req('PATCH', id, body) - - def modify_type(self, id, type): - body = json.dumps({'type': type}) - return self._req('PATCH', id, body) - - def modify_kernel_name(self, id, kernel_name): - body = json.dumps({'kernel': {'name': kernel_name}}) - return self._req('PATCH', id, body) - - def modify_kernel_id(self, id, kernel_id): - # Also send a dummy name to show that id takes precedence. - body = json.dumps({'kernel': {'id': kernel_id, 'name': 'foo'}}) - return self._req('PATCH', id, body) - - def delete(self, id): - return self._req('DELETE', id) - - -class SessionAPITest(NotebookTestBase): - """Test the sessions web service API""" - def setUp(self): - nbdir = self.notebook_dir - subdir = pjoin(nbdir, 'foo') - - try: - os.mkdir(subdir) - except OSError as e: - # Deleting the folder in an earlier test may have failed - if e.errno != errno.EEXIST: - raise - self.addCleanup(partial(shutil.rmtree, subdir, ignore_errors=True)) - - with io.open(pjoin(subdir, 'nb1.ipynb'), 'w', encoding='utf-8') as f: - nb = new_notebook() - write(nb, f, version=4) - - self.sess_api = SessionAPI(self.request) - - @self.addCleanup - def cleanup_sessions(): - for session in self.sess_api.list().json(): - self.sess_api.delete(session['id']) - - # This is necessary in some situations on Windows: without it, it - # fails to delete the directory because something is still using - # it. I think there is a brief period after the kernel terminates - # where Windows still treats its working directory as in use. On my - # Windows VM, 0.01s is not long enough, but 0.1s appears to work - # reliably. -- TK, 15 December 2014 - time.sleep(0.1) - - def test_create(self): - sessions = self.sess_api.list().json() - self.assertEqual(len(sessions), 0) - - resp = self.sess_api.create('foo/nb1.ipynb') - self.assertEqual(resp.status_code, 201) - newsession = resp.json() - self.assertIn('id', newsession) - self.assertEqual(newsession['path'], 'foo/nb1.ipynb') - self.assertEqual(newsession['type'], 'notebook') - self.assertEqual(resp.headers['Location'], self.url_prefix + 'api/sessions/{0}'.format(newsession['id'])) - - sessions = self.sess_api.list().json() - self.assertEqual(sessions, [newsession]) - - # Retrieve it - sid = newsession['id'] - got = self.sess_api.get(sid).json() - self.assertEqual(got, newsession) - - def test_create_file_session(self): - resp = self.sess_api.create('foo/nb1.py', type='file') - self.assertEqual(resp.status_code, 201) - newsession = resp.json() - self.assertEqual(newsession['path'], 'foo/nb1.py') - self.assertEqual(newsession['type'], 'file') - - def test_create_console_session(self): - resp = self.sess_api.create('foo/abc123', type='console') - self.assertEqual(resp.status_code, 201) - newsession = resp.json() - self.assertEqual(newsession['path'], 'foo/abc123') - self.assertEqual(newsession['type'], 'console') - - def test_create_deprecated(self): - resp = self.sess_api.create_deprecated('foo/nb1.ipynb') - self.assertEqual(resp.status_code, 201) - newsession = resp.json() - self.assertEqual(newsession['path'], 'foo/nb1.ipynb') - self.assertEqual(newsession['type'], 'notebook') - self.assertEqual(newsession['notebook']['path'], 'foo/nb1.ipynb') - - def test_create_with_kernel_id(self): - # create a new kernel - r = self.request('POST', 'api/kernels') - r.raise_for_status() - kernel = r.json() - - resp = self.sess_api.create('foo/nb1.ipynb', kernel_id=kernel['id']) - self.assertEqual(resp.status_code, 201) - newsession = resp.json() - self.assertIn('id', newsession) - self.assertEqual(newsession['path'], 'foo/nb1.ipynb') - self.assertEqual(newsession['kernel']['id'], kernel['id']) - self.assertEqual(resp.headers['Location'], self.url_prefix + 'api/sessions/{0}'.format(newsession['id'])) - - sessions = self.sess_api.list().json() - self.assertEqual(sessions, [newsession]) - - # Retrieve it - sid = newsession['id'] - got = self.sess_api.get(sid).json() - self.assertEqual(got, newsession) - - def test_delete(self): - newsession = self.sess_api.create('foo/nb1.ipynb').json() - sid = newsession['id'] - - resp = self.sess_api.delete(sid) - self.assertEqual(resp.status_code, 204) - - sessions = self.sess_api.list().json() - self.assertEqual(sessions, []) - - with assert_http_error(404): - self.sess_api.get(sid) - - def test_modify_path(self): - newsession = self.sess_api.create('foo/nb1.ipynb').json() - sid = newsession['id'] - - changed = self.sess_api.modify_path(sid, 'nb2.ipynb').json() - self.assertEqual(changed['id'], sid) - self.assertEqual(changed['path'], 'nb2.ipynb') - - def test_modify_path_deprecated(self): - newsession = self.sess_api.create('foo/nb1.ipynb').json() - sid = newsession['id'] - - changed = self.sess_api.modify_path_deprecated(sid, 'nb2.ipynb').json() - self.assertEqual(changed['id'], sid) - self.assertEqual(changed['notebook']['path'], 'nb2.ipynb') - - def test_modify_type(self): - newsession = self.sess_api.create('foo/nb1.ipynb').json() - sid = newsession['id'] - - changed = self.sess_api.modify_type(sid, 'console').json() - self.assertEqual(changed['id'], sid) - self.assertEqual(changed['type'], 'console') - - def test_modify_kernel_name(self): - before = self.sess_api.create('foo/nb1.ipynb').json() - sid = before['id'] - - after = self.sess_api.modify_kernel_name(sid, before['kernel']['name']).json() - self.assertEqual(after['id'], sid) - self.assertEqual(after['path'], before['path']) - self.assertEqual(after['type'], before['type']) - self.assertNotEqual(after['kernel']['id'], before['kernel']['id']) - - # check kernel list, to be sure previous kernel was cleaned up - r = self.request('GET', 'api/kernels') - r.raise_for_status() - kernel_list = r.json() - after['kernel'].pop('last_activity') - [ k.pop('last_activity') for k in kernel_list ] - self.assertEqual(kernel_list, [after['kernel']]) - - def test_modify_kernel_id(self): - before = self.sess_api.create('foo/nb1.ipynb').json() - sid = before['id'] - - # create a new kernel - r = self.request('POST', 'api/kernels') - r.raise_for_status() - kernel = r.json() - - # Attach our session to the existing kernel - after = self.sess_api.modify_kernel_id(sid, kernel['id']).json() - self.assertEqual(after['id'], sid) - self.assertEqual(after['path'], before['path']) - self.assertEqual(after['type'], before['type']) - self.assertNotEqual(after['kernel']['id'], before['kernel']['id']) - self.assertEqual(after['kernel']['id'], kernel['id']) - - # check kernel list, to be sure previous kernel was cleaned up - r = self.request('GET', 'api/kernels') - r.raise_for_status() - kernel_list = r.json() - - kernel.pop('last_activity') - [ k.pop('last_activity') for k in kernel_list ] - self.assertEqual(kernel_list, [kernel]) - - -class AsyncSessionAPITest(SessionAPITest): - """Test the sessions web service API using the AsyncMappingKernelManager""" - - @classmethod - def setup_class(cls): - if not async_testing_enabled: # Can be removed once jupyter_client >= 6.1 is required. - raise SkipTest("AsyncSessionAPITest tests skipped due to down-level jupyter_client!") - super(AsyncSessionAPITest, cls).setup_class() - - @classmethod - def get_argv(cls): - argv = super(AsyncSessionAPITest, cls).get_argv() - - # Before we extend the argv with the class, ensure that appropriate jupyter_client is available. - # if not available, don't set kernel_manager_class, resulting in the repeat of sync-based tests. - if async_testing_enabled: - argv.extend(['--NotebookApp.kernel_manager_class=' - 'notebook.services.kernels.kernelmanager.AsyncMappingKernelManager']) - - return argv diff --git a/notebook/services/shutdown.py b/notebook/services/shutdown.py deleted file mode 100644 index 78d1f2ad6..000000000 --- a/notebook/services/shutdown.py +++ /dev/null @@ -1,15 +0,0 @@ -"""HTTP handler to shut down the notebook server. -""" -from tornado import web, ioloop -from notebook.base.handlers import IPythonHandler - -class ShutdownHandler(IPythonHandler): - @web.authenticated - def post(self): - self.log.info("Shutting down on /api/shutdown request.") - ioloop.IOLoop.current().stop() - - -default_handlers = [ - (r"/api/shutdown", ShutdownHandler), -] diff --git a/notebook/static/acc_overwrite.less b/notebook/static/acc_overwrite.less deleted file mode 100644 index 4209ea633..000000000 --- a/notebook/static/acc_overwrite.less +++ /dev/null @@ -1,61 +0,0 @@ -//This is file created for overwriting some of bootstrap element color in order to satisfiy the color contrast greater than 4.5:1. - -.btn-danger{ - color: #ffffff; - background-color: #df0404; - border-color: #df0404; -} - -.btn-warning{ - color: #ffffff; - background-color:#b46102; - border-color: #b46102; -} - -@link-color: #296eaa; - -.close { - float: right; - font-size: (@font-size-base * 1.5); - font-weight: @close-font-weight; - line-height: 1; - color: @close-color; - text-shadow: @close-text-shadow; - .opacity(.6); - - &:hover, - &:focus { - color: @close-color; - text-decoration: none; - cursor: pointer; - .opacity(1.0); -} button& { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; - appearance: none; - } -} - -.navbar-nav { - > li > a { - color: @navbar-default-link-color; - // To make keyboard focus clearly visible on the Controls(File,Edit,View,Insert,Cell...etc)present on the menubar. - //&:hover, //To use browser's hover default value - &:focus { - /* -webkit-focus-ring-color = '#5B9DD9' */ - outline: -webkit-focus-ring-color auto 5px; - // color: @navbar-default-link-hover-color; - // background-color: @navbar-default-link-hover-bg; - } - } -} - -.menu_focus_highlight{ - a:focus { - outline: -webkit-focus-ring-color auto 5px; -} -} - diff --git a/notebook/static/auth/css/override.css b/notebook/static/auth/css/override.css deleted file mode 100644 index 0cb116ec2..000000000 --- a/notebook/static/auth/css/override.css +++ /dev/null @@ -1,8 +0,0 @@ -/*This file contains any manual css for this page that needs to override the global styles. -This is only required when different pages style the same element differently. This is just -a hack to deal with our current css styles and no new styling should be added in this file.*/ - -#ipython-main-app { - padding-top: 50px; - text-align: center; -} diff --git a/notebook/static/auth/js/loginmain.js b/notebook/static/auth/js/loginmain.js deleted file mode 100644 index 0c6b661f7..000000000 --- a/notebook/static/auth/js/loginmain.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -define(['jquery', 'base/js/namespace', 'base/js/page'], function($, IPython, page) { - function login_main() { - var page_instance = new page.Page('div#header', 'div#site'); - page_instance.show(); - $('input#password_input').focus(); - IPython.page = page_instance; - } - return login_main; -}); diff --git a/notebook/static/auth/js/loginwidget.js b/notebook/static/auth/js/loginwidget.js deleted file mode 100644 index 8b68d3e84..000000000 --- a/notebook/static/auth/js/loginwidget.js +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -define([ - 'jquery', - 'base/js/utils', -], function($, utils){ - "use strict"; - - var LoginWidget = function (selector, options) { - options = options || {}; - this.base_url = options.base_url || utils.get_body_data("baseUrl"); - this.selector = selector; - if (this.selector !== undefined) { - this.element = $(selector); - this.bind_events(); - } - }; - - - LoginWidget.prototype.bind_events = function () { - var that = this; - this.element.find("button#logout").click(function () { - window.location = utils.url_path_join( - that.base_url, - "logout" - ); - }); - this.element.find("button#login").click(function () { - window.location = utils.url_path_join( - that.base_url, - "login" - ); - }); - }; - - return {'LoginWidget': LoginWidget}; -}); diff --git a/notebook/static/auth/js/logoutmain.js b/notebook/static/auth/js/logoutmain.js deleted file mode 100644 index 41e775053..000000000 --- a/notebook/static/auth/js/logoutmain.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -define(['base/js/namespace', 'base/js/page'], function(IPython, page) { - function logout_main() { - var page_instance = new page.Page('div#header', 'div#site'); - page_instance.show(); - - IPython.page = page_instance; - } - return logout_main; -}); diff --git a/notebook/static/auth/js/main.js b/notebook/static/auth/js/main.js deleted file mode 100644 index 68d7871c5..000000000 --- a/notebook/static/auth/js/main.js +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -define(['./loginmain', './logoutmain', 'bidi/bidi'], function (login_main, logout_main, bidi) { - if(bidi.isMirroringEnabled()){ - $("body").attr("dir","rtl"); - } - return { - login_main: login_main, - logout_main: logout_main - }; -}); diff --git a/notebook/static/auth/less/login.less b/notebook/static/auth/less/login.less deleted file mode 100644 index 8a4ce3ffc..000000000 --- a/notebook/static/auth/less/login.less +++ /dev/null @@ -1,23 +0,0 @@ -// Custom styles for login.html -.center-nav { - display: inline-block; - // pull the lower margin back - margin-bottom: -4px; -} - -[dir="rtl"] .center-nav { - form.pull-left { - .pull-right(); - } - .navbar-text { - float: right; - } -} - -[dir="rtl"] .navbar-inner { - text-align: right; -} - -[dir="rtl"] div.text-left { - .text-right(); -} diff --git a/notebook/static/auth/less/logout.less b/notebook/static/auth/less/logout.less deleted file mode 100644 index 63cd701c9..000000000 --- a/notebook/static/auth/less/logout.less +++ /dev/null @@ -1,2 +0,0 @@ -// Custom styles for logout.html - diff --git a/notebook/static/auth/less/style.less b/notebook/static/auth/less/style.less deleted file mode 100644 index 4d1919cc0..000000000 --- a/notebook/static/auth/less/style.less +++ /dev/null @@ -1,7 +0,0 @@ -/*! -* -* IPython auth -* -*/ -@import "login.less"; -@import "logout.less"; \ No newline at end of file diff --git a/notebook/static/base/images/favicon-busy-1.ico b/notebook/static/base/images/favicon-busy-1.ico deleted file mode 100644 index 5b46a8226..000000000 Binary files a/notebook/static/base/images/favicon-busy-1.ico and /dev/null differ diff --git a/notebook/static/base/images/favicon-busy-2.ico b/notebook/static/base/images/favicon-busy-2.ico deleted file mode 100644 index 4a8b841c2..000000000 Binary files a/notebook/static/base/images/favicon-busy-2.ico and /dev/null differ diff --git a/notebook/static/base/images/favicon-busy-3.ico b/notebook/static/base/images/favicon-busy-3.ico deleted file mode 100644 index b5edce573..000000000 Binary files a/notebook/static/base/images/favicon-busy-3.ico and /dev/null differ diff --git a/notebook/static/base/images/favicon-file.ico b/notebook/static/base/images/favicon-file.ico deleted file mode 100644 index 8167018cd..000000000 Binary files a/notebook/static/base/images/favicon-file.ico and /dev/null differ diff --git a/notebook/static/base/images/favicon-notebook.ico b/notebook/static/base/images/favicon-notebook.ico deleted file mode 100644 index 4537e2d98..000000000 Binary files a/notebook/static/base/images/favicon-notebook.ico and /dev/null differ diff --git a/notebook/static/base/images/favicon-terminal.ico b/notebook/static/base/images/favicon-terminal.ico deleted file mode 100644 index ace499a33..000000000 Binary files a/notebook/static/base/images/favicon-terminal.ico and /dev/null differ diff --git a/notebook/static/base/images/favicon.ico b/notebook/static/base/images/favicon.ico deleted file mode 100644 index 2d1bcff7c..000000000 Binary files a/notebook/static/base/images/favicon.ico and /dev/null differ diff --git a/notebook/static/base/images/logo.png b/notebook/static/base/images/logo.png deleted file mode 100644 index 3f3f57ff3..000000000 Binary files a/notebook/static/base/images/logo.png and /dev/null differ diff --git a/notebook/static/base/js/dialog.js b/notebook/static/base/js/dialog.js deleted file mode 100644 index 77d81185f..000000000 --- a/notebook/static/base/js/dialog.js +++ /dev/null @@ -1,433 +0,0 @@ -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -define(['jquery', - 'codemirror/lib/codemirror', - 'bootstrap', - 'base/js/i18n'], - function($, CodeMirror, bs, i18n) { - "use strict"; - - /** - * A wrapper around bootstrap modal for easier use - * Pass it an option dictionary with the following properties: - * - * - body : or , main content of the dialog - * if pass a it will be wrapped in a p tag and - * html element escaped, unless you specify sanitize=false - * option. - * - title : Dialog title, default to empty string. - * - buttons : dict of btn_options who keys are button label. - * see btn_options below for description - * - open : callback to trigger on dialog open. - * - destroy: - * - notebook : notebook instance - * - keyboard_manager: keyboard manager instance. - * - * Unlike bootstrap modals, the backdrop options is set by default - * to 'static'. - * - * The rest of the options are passed as is to bootstrap modals. - * - * btn_options: dict with the following property: - * - * - click : callback to trigger on click - * - class : css classes to add to button. - * - * - * - **/ - var modal = function (options) { - - var modal = $("
") - .addClass("modal") - .addClass("fade") - .attr("role", "dialog"); - var dialog = $("
") - .addClass("modal-dialog") - .appendTo(modal); - var dialog_content = $("
") - .addClass("modal-content") - .appendTo(dialog); - if(typeof(options.body) === 'string' && options.sanitize !== false){ - options.body = $("

").text(options.body); - } - dialog_content.append( - $("

") - .addClass("modal-header") - .mousedown(function() { - $(".modal").draggable({handle: '.modal-header'}); - }) - .append($("