From 5729079a02f41fdb682a289ae02fb5e0a5482427 Mon Sep 17 00:00:00 2001 From: Nayeon Keum Date: Wed, 2 Aug 2023 21:40:49 +0900 Subject: [PATCH] [feat/#56] Add: student server's webssh dir --- .../student-ubuntu/webssh/Dockerfile.bak | 18 + .../images/student-ubuntu/webssh/LICENSE | 21 + .../images/student-ubuntu/webssh/MANIFEST.in | 13 + .../images/student-ubuntu/webssh/README.md | 212 +++++ .../images/student-ubuntu/webssh/README.rst | 246 +++++ .../webssh/docker-compose.yml.bak | 6 + .../student-ubuntu/webssh/preview/login.png | Bin 0 -> 60907 bytes .../webssh/preview/terminal.png | Bin 0 -> 98917 bytes .../student-ubuntu/webssh/requirements.txt | 2 + resources/images/student-ubuntu/webssh/run.py | 5 + .../images/student-ubuntu/webssh/setup.cfg | 9 + .../images/student-ubuntu/webssh/setup.py | 37 + .../student-ubuntu/webssh/tests/__init__.py | 0 .../student-ubuntu/webssh/tests/data/cert.crt | 21 + .../student-ubuntu/webssh/tests/data/cert.key | 28 + .../webssh/tests/data/fonts/fake-font | 0 .../webssh/tests/data/known_hosts_example | 1 + .../webssh/tests/data/known_hosts_example2 | 1 + .../webssh/tests/data/known_hosts_example3 | 1 + .../webssh/tests/data/test_ed25519.key | 8 + .../tests/data/test_ed25519_password.key | 8 + .../webssh/tests/data/test_known_hosts | 1 + .../webssh/tests/data/test_new_dsa.key | 21 + .../tests/data/test_new_rsa_password.key | 39 + .../webssh/tests/data/test_rsa.key | 15 + .../webssh/tests/data/test_rsa_password.key | 18 + .../webssh/tests/data/user_rsa_key | 15 + .../student-ubuntu/webssh/tests/sshserver.py | 213 +++++ .../student-ubuntu/webssh/tests/test_app.py | 792 ++++++++++++++++ .../webssh/tests/test_handler.py | 317 +++++++ .../student-ubuntu/webssh/tests/test_main.py | 22 + .../webssh/tests/test_policy.py | 123 +++ .../webssh/tests/test_settings.py | 187 ++++ .../student-ubuntu/webssh/tests/test_utils.py | 127 +++ .../student-ubuntu/webssh/tests/utils.py | 52 ++ .../student-ubuntu/webssh/webssh/__init__.py | 10 + .../student-ubuntu/webssh/webssh/_version.py | 2 + .../student-ubuntu/webssh/webssh/handler.py | 603 ++++++++++++ .../student-ubuntu/webssh/webssh/main.py | 58 ++ .../student-ubuntu/webssh/webssh/policy.py | 86 ++ .../student-ubuntu/webssh/webssh/settings.py | 198 ++++ .../webssh/static/css/bootstrap.min.css | 7 + .../webssh/static/css/fullscreen.min.css | 2 + .../webssh/webssh/static/css/xterm.min.css | 1 + .../webssh/webssh/static/img/favicon.png | Bin 0 -> 5953 bytes .../webssh/webssh/static/js/bootstrap.min.js | 7 + .../webssh/webssh/static/js/jquery.min.js | 2 + .../webssh/webssh/static/js/main.js | 858 ++++++++++++++++++ .../webssh/webssh/static/js/popper.min.js | 5 + .../webssh/static/js/xterm-addon-fit.min.js | 2 + .../webssh/webssh/static/js/xterm.min.js | 2 + .../webssh/webssh/templates/index.html | 101 +++ .../student-ubuntu/webssh/webssh/utils.py | 145 +++ .../student-ubuntu/webssh/webssh/worker.py | 134 +++ 54 files changed, 4802 insertions(+) create mode 100644 resources/images/student-ubuntu/webssh/Dockerfile.bak create mode 100644 resources/images/student-ubuntu/webssh/LICENSE create mode 100644 resources/images/student-ubuntu/webssh/MANIFEST.in create mode 100644 resources/images/student-ubuntu/webssh/README.md create mode 100644 resources/images/student-ubuntu/webssh/README.rst create mode 100644 resources/images/student-ubuntu/webssh/docker-compose.yml.bak create mode 100644 resources/images/student-ubuntu/webssh/preview/login.png create mode 100644 resources/images/student-ubuntu/webssh/preview/terminal.png create mode 100644 resources/images/student-ubuntu/webssh/requirements.txt create mode 100644 resources/images/student-ubuntu/webssh/run.py create mode 100644 resources/images/student-ubuntu/webssh/setup.cfg create mode 100644 resources/images/student-ubuntu/webssh/setup.py create mode 100644 resources/images/student-ubuntu/webssh/tests/__init__.py create mode 100644 resources/images/student-ubuntu/webssh/tests/data/cert.crt create mode 100644 resources/images/student-ubuntu/webssh/tests/data/cert.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/fonts/fake-font create mode 100644 resources/images/student-ubuntu/webssh/tests/data/known_hosts_example create mode 100644 resources/images/student-ubuntu/webssh/tests/data/known_hosts_example2 create mode 100644 resources/images/student-ubuntu/webssh/tests/data/known_hosts_example3 create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_ed25519.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_ed25519_password.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_known_hosts create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_new_dsa.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_new_rsa_password.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_rsa.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/test_rsa_password.key create mode 100644 resources/images/student-ubuntu/webssh/tests/data/user_rsa_key create mode 100644 resources/images/student-ubuntu/webssh/tests/sshserver.py create mode 100644 resources/images/student-ubuntu/webssh/tests/test_app.py create mode 100644 resources/images/student-ubuntu/webssh/tests/test_handler.py create mode 100644 resources/images/student-ubuntu/webssh/tests/test_main.py create mode 100644 resources/images/student-ubuntu/webssh/tests/test_policy.py create mode 100644 resources/images/student-ubuntu/webssh/tests/test_settings.py create mode 100644 resources/images/student-ubuntu/webssh/tests/test_utils.py create mode 100644 resources/images/student-ubuntu/webssh/tests/utils.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/__init__.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/_version.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/handler.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/main.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/policy.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/settings.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/css/bootstrap.min.css create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/css/fullscreen.min.css create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/css/xterm.min.css create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/img/favicon.png create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/js/bootstrap.min.js create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/js/jquery.min.js create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/js/main.js create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/js/popper.min.js create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/js/xterm-addon-fit.min.js create mode 100644 resources/images/student-ubuntu/webssh/webssh/static/js/xterm.min.js create mode 100644 resources/images/student-ubuntu/webssh/webssh/templates/index.html create mode 100644 resources/images/student-ubuntu/webssh/webssh/utils.py create mode 100644 resources/images/student-ubuntu/webssh/webssh/worker.py diff --git a/resources/images/student-ubuntu/webssh/Dockerfile.bak b/resources/images/student-ubuntu/webssh/Dockerfile.bak new file mode 100644 index 0000000..cbf7f71 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/Dockerfile.bak @@ -0,0 +1,18 @@ +FROM python:3-alpine + +LABEL maintainer='' +LABEL version='0.0.0-dev.0-build.0' + +ADD . /code +WORKDIR /code +RUN \ + apk add --no-cache libc-dev libffi-dev gcc && \ + pip install -r requirements.txt --no-cache-dir && \ + apk del gcc libc-dev libffi-dev && \ + addgroup webssh && \ + adduser -Ss /bin/false -g webssh webssh && \ + chown -R webssh:webssh /code + +EXPOSE 8888/tcp +USER webssh +CMD ["python", "run.py"] diff --git a/resources/images/student-ubuntu/webssh/LICENSE b/resources/images/student-ubuntu/webssh/LICENSE new file mode 100644 index 0000000..8d1036e --- /dev/null +++ b/resources/images/student-ubuntu/webssh/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Shengdun Hua + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/resources/images/student-ubuntu/webssh/MANIFEST.in b/resources/images/student-ubuntu/webssh/MANIFEST.in new file mode 100644 index 0000000..bb85ddd --- /dev/null +++ b/resources/images/student-ubuntu/webssh/MANIFEST.in @@ -0,0 +1,13 @@ +include LICENSE + +recursive-include tests * +prune tests/__pycache__ +prune tests/.pytest_cache + +recursive-include webssh * +prune webssh/__pycache__ +prune webssh/.pytest_cache + +global-exclude *.pyc +global-exclude *.log +global-exclude .coverage diff --git a/resources/images/student-ubuntu/webssh/README.md b/resources/images/student-ubuntu/webssh/README.md new file mode 100644 index 0000000..8d91036 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/README.md @@ -0,0 +1,212 @@ +## WebSSH + +[![Build Status](https://travis-ci.org/huashengdun/webssh.svg?branch=master)](https://travis-ci.org/huashengdun/webssh) +[![codecov](https://codecov.io/gh/huashengdun/webssh/branch/master/graph/badge.svg)](https://codecov.io/gh/huashengdun/webssh) +![PyPI - Python Version](https://img.shields.io/pypi/pyversions/webssh.svg) +![PyPI](https://img.shields.io/pypi/v/webssh.svg) + + +### Introduction + +A simple web application to be used as an ssh client to connect to your ssh servers. It is written in Python, base on tornado, paramiko and xterm.js. + +### Features + +* SSH password authentication supported, including empty password. +* SSH public-key authentication supported, including DSA RSA ECDSA Ed25519 keys. +* Encrypted keys supported. +* Two-Factor Authentication (time-based one-time password) supported. +* Fullscreen terminal supported. +* Terminal window resizable. +* Auto detect the ssh server's default encoding. +* Modern browsers including Chrome, Firefox, Safari, Edge, Opera supported. + + +### Preview + +![Login](preview/login.png) +![Terminal](preview/terminal.png) + + +### How it works +``` ++---------+ http +--------+ ssh +-----------+ +| browser | <==========> | webssh | <=======> | ssh server| ++---------+ websocket +--------+ ssh +-----------+ +``` + +### Requirements + +* Python 3.8+ + + +### Quickstart + +1. Install this app, run command `pip install webssh` +2. Start a webserver, run command `wssh` +3. Open your browser, navigate to `127.0.0.1:8888` +4. Input your data, submit the form. + + +### Server options + +```bash +# start a http server with specified listen address and listen port +wssh --address='2.2.2.2' --port=8000 + +# start a https server, certfile and keyfile must be passed +wssh --certfile='/path/to/cert.crt' --keyfile='/path/to/cert.key' + +# missing host key policy +wssh --policy=reject + +# logging level +wssh --logging=debug + +# log to file +wssh --log-file-prefix=main.log + +# more options +wssh --help +``` + +### Browser console + +```javascript +// connect to your ssh server +wssh.connect(hostname, port, username, password, privatekey, passphrase, totp); + +// pass an object to wssh.connect +var opts = { + hostname: 'hostname', + port: 'port', + username: 'username', + password: 'password', + privatekey: 'the private key text', + passphrase: 'passphrase', + totp: 'totp' +}; +wssh.connect(opts); + +// without an argument, wssh will use the form data to connect +wssh.connect(); + +// set a new encoding for client to use +wssh.set_encoding(encoding); + +// reset encoding to use the default one +wssh.reset_encoding(); + +// send a command to the server +wssh.send('ls -l'); +``` + +### Custom Font + +To use custom font, put your font file in the directory `webssh/static/css/fonts/` and restart the server. + +### URL Arguments + +Support passing arguments by url (query or fragment) like following examples: + +Passing form data (password must be encoded in base64, privatekey not supported) +```bash +http://localhost:8888/?hostname=xx&username=yy&password=str_base64_encoded +``` + +Passing a terminal background color +```bash +http://localhost:8888/#bgcolor=green +``` + +Passing a terminal font color +```bash +http://localhost:8888/#fontcolor=red +``` + +Passing a user defined title +```bash +http://localhost:8888/?title=my-ssh-server +``` + +Passing an encoding +```bash +http://localhost:8888/#encoding=gbk +``` + +Passing a font size +```bash +http://localhost:8888/#fontsize=24 +``` + +Passing a command executed right after login +```bash +http://localhost:8888/?command=pwd +``` + +Passing a terminal type +```bash +http://localhost:8888/?term=xterm-256color +``` + +### Use Docker + +Start up the app +``` +docker-compose up +``` + +Tear down the app +``` +docker-compose down +``` + +### Tests + +Requirements +``` +pip install pytest pytest-cov codecov flake8 mock +``` + +Use unittest to run all tests +``` +python -m unittest discover tests +``` + +Use pytest to run all tests +``` +python -m pytest tests +``` + +### Deployment + +Running behind an Nginx server + +```bash +wssh --address='127.0.0.1' --port=8888 --policy=reject +``` +```nginx +# Nginx config example +location / { + proxy_pass http://127.0.0.1:8888; + proxy_http_version 1.1; + proxy_read_timeout 300; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Real-PORT $remote_port; +} +``` + +Running as a standalone server +```bash +wssh --port=8080 --sslport=4433 --certfile='cert.crt' --keyfile='cert.key' --xheaders=False --policy=reject +``` + + +### Tips + +* For whatever deployment choice you choose, don't forget to enable SSL. +* By default plain http requests from a public network will be either redirected or blocked and being redirected takes precedence over being blocked. +* Try to use reject policy as the missing host key policy along with your verified known_hosts, this will prevent man-in-the-middle attacks. The idea is that it checks the system host keys file("~/.ssh/known_hosts") and the application host keys file("./known_hosts") in order, if the ssh server's hostname is not found or the key is not matched, the connection will be aborted. diff --git a/resources/images/student-ubuntu/webssh/README.rst b/resources/images/student-ubuntu/webssh/README.rst new file mode 100644 index 0000000..dd5771a --- /dev/null +++ b/resources/images/student-ubuntu/webssh/README.rst @@ -0,0 +1,246 @@ +WebSSH +------ + +|Build Status| |codecov| |PyPI - Python Version| |PyPI| + +Introduction +~~~~~~~~~~~~ + +A simple web application to be used as an ssh client to connect to your +ssh servers. It is written in Python, base on tornado, paramiko and +xterm.js. + +Features +~~~~~~~~ + +- SSH password authentication supported, including empty password. +- SSH public-key authentication supported, including DSA RSA ECDSA + Ed25519 keys. +- Encrypted keys supported. +- Two-Factor Authentication (time-based one-time password) supported. +- Fullscreen terminal supported. +- Terminal window resizable. +- Auto detect the ssh server's default encoding. +- Modern browsers including Chrome, Firefox, Safari, Edge, Opera + supported. + +Preview +~~~~~~~ + +|Login| |Terminal| + +How it works +~~~~~~~~~~~~ + +:: + + +---------+ http +--------+ ssh +-----------+ + | browser | <==========> | webssh | <=======> | ssh server| + +---------+ websocket +--------+ ssh +-----------+ + +Requirements +~~~~~~~~~~~~ + +- Python 3.8+ + +Quickstart +~~~~~~~~~~ + +1. Install this app, run command ``pip install webssh`` +2. Start a webserver, run command ``wssh`` +3. Open your browser, navigate to ``127.0.0.1:8888`` +4. Input your data, submit the form. + +Server options +~~~~~~~~~~~~~~ + +.. code:: bash + + # start a http server with specified listen address and listen port + wssh --address='2.2.2.2' --port=8000 + + # start a https server, certfile and keyfile must be passed + wssh --certfile='/path/to/cert.crt' --keyfile='/path/to/cert.key' + + # missing host key policy + wssh --policy=reject + + # logging level + wssh --logging=debug + + # log to file + wssh --log-file-prefix=main.log + + # more options + wssh --help + +Browser console +~~~~~~~~~~~~~~~ + +.. code:: javascript + + // connect to your ssh server + wssh.connect(hostname, port, username, password, privatekey, passphrase, totp); + + // pass an object to wssh.connect + var opts = { + hostname: 'hostname', + port: 'port', + username: 'username', + password: 'password', + privatekey: 'the private key text', + passphrase: 'passphrase', + totp: 'totp' + }; + wssh.connect(opts); + + // without an argument, wssh will use the form data to connect + wssh.connect(); + + // set a new encoding for client to use + wssh.set_encoding(encoding); + + // reset encoding to use the default one + wssh.reset_encoding(); + + // send a command to the server + wssh.send('ls -l'); + +Custom Font +~~~~~~~~~~~ + +To use custom font, put your font file in the directory +``webssh/static/css/fonts/`` and restart the server. + +URL Arguments +~~~~~~~~~~~~~ + +Support passing arguments by url (query or fragment) like following +examples: + +Passing form data (password must be encoded in base64, privatekey not +supported) + +.. code:: bash + + http://localhost:8888/?hostname=xx&username=yy&password=str_base64_encoded + +Passing a terminal background color + +.. code:: bash + + http://localhost:8888/#bgcolor=green + +Passing a user defined title + +.. code:: bash + + http://localhost:8888/?title=my-ssh-server + +Passing an encoding + +.. code:: bash + + http://localhost:8888/#encoding=gbk + +Passing a command executed right after login + +.. code:: bash + + http://localhost:8888/?command=pwd + +Passing a terminal type + +.. code:: bash + + http://localhost:8888/?term=xterm-256color + +Use Docker +~~~~~~~~~~ + +Start up the app + +:: + + docker-compose up + +Tear down the app + +:: + + docker-compose down + +Tests +~~~~~ + +Requirements + +:: + + pip install pytest pytest-cov codecov flake8 mock + +Use unittest to run all tests + +:: + + python -m unittest discover tests + +Use pytest to run all tests + +:: + + python -m pytest tests + +Deployment +~~~~~~~~~~ + +Running behind an Nginx server + +.. code:: bash + + wssh --address='127.0.0.1' --port=8888 --policy=reject + +.. code:: nginx + + # Nginx config example + location / { + proxy_pass http://127.0.0.1:8888; + proxy_http_version 1.1; + proxy_read_timeout 300; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Real-PORT $remote_port; + } + +Running as a standalone server + +.. code:: bash + + wssh --port=8080 --sslport=4433 --certfile='cert.crt' --keyfile='cert.key' --xheaders=False --policy=reject + +Tips +~~~~ + +- For whatever deployment choice you choose, don't forget to enable + SSL. +- By default plain http requests from a public network will be either + redirected or blocked and being redirected takes precedence over + being blocked. +- Try to use reject policy as the missing host key policy along with + your verified known\_hosts, this will prevent man-in-the-middle + attacks. The idea is that it checks the system host keys + file("~/.ssh/known\_hosts") and the application host keys + file("./known\_hosts") in order, if the ssh server's hostname is not + found or the key is not matched, the connection will be aborted. + +.. |Build Status| image:: https://travis-ci.org/huashengdun/webssh.svg?branch=master + :target: https://travis-ci.org/huashengdun/webssh +.. |codecov| image:: https://codecov.io/gh/huashengdun/webssh/branch/master/graph/badge.svg + :target: https://codecov.io/gh/huashengdun/webssh +.. |PyPI - Python Version| image:: https://img.shields.io/pypi/pyversions/webssh.svg +.. |PyPI| image:: https://img.shields.io/pypi/v/webssh.svg +.. |Login| image:: https://github.com/huashengdun/webssh/raw/master/preview/login.png +.. |Terminal| image:: https://github.com/huashengdun/webssh/raw/master/preview/terminal.png + diff --git a/resources/images/student-ubuntu/webssh/docker-compose.yml.bak b/resources/images/student-ubuntu/webssh/docker-compose.yml.bak new file mode 100644 index 0000000..315cee6 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/docker-compose.yml.bak @@ -0,0 +1,6 @@ +version: '3' +services: + web: + build: . + ports: + - "8888:8888" diff --git a/resources/images/student-ubuntu/webssh/preview/login.png b/resources/images/student-ubuntu/webssh/preview/login.png new file mode 100644 index 0000000000000000000000000000000000000000..b83d49c247fc4376d1a74a69f0448421d8ac9bcd GIT binary patch literal 60907 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

    (}*qqgG3K^ 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Ҟ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 M_d3_`k1Kcn6KImsHUIzs literal 0 HcmV?d00001 diff --git a/resources/images/student-ubuntu/webssh/requirements.txt b/resources/images/student-ubuntu/webssh/requirements.txt new file mode 100644 index 0000000..18ee6b3 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/requirements.txt @@ -0,0 +1,2 @@ +paramiko==3.0.0 +tornado==6.2.0 diff --git a/resources/images/student-ubuntu/webssh/run.py b/resources/images/student-ubuntu/webssh/run.py new file mode 100644 index 0000000..0585233 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/run.py @@ -0,0 +1,5 @@ +from webssh.main import main + + +if __name__ == '__main__': + main() diff --git a/resources/images/student-ubuntu/webssh/setup.cfg b/resources/images/student-ubuntu/webssh/setup.cfg new file mode 100644 index 0000000..b798b26 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/setup.cfg @@ -0,0 +1,9 @@ +[wheel] +universal = 1 + +[metadata] +license_file = LICENSE + +[flake8] +exclude = .git,build,dist,tests, __init__.py +max-line-length = 79 diff --git a/resources/images/student-ubuntu/webssh/setup.py b/resources/images/student-ubuntu/webssh/setup.py new file mode 100644 index 0000000..dd211fb --- /dev/null +++ b/resources/images/student-ubuntu/webssh/setup.py @@ -0,0 +1,37 @@ +import codecs +from setuptools import setup +from webssh._version import __version__ as version + + +with codecs.open('README.rst', encoding='utf-8') as f: + long_description = f.read() + + +setup( + name='webssh', + version=version, + description='Web based ssh client', + long_description=long_description, + author='Shengdun Hua', + author_email='webmaster0115@gmail.com', + url='https://github.com/huashengdun/webssh', + packages=['webssh'], + entry_points=''' + [console_scripts] + wssh = webssh.main:main + ''', + license='MIT', + include_package_data=True, + classifiers=[ + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + ], + install_requires=[ + 'tornado>=4.5.0', + 'paramiko>=2.3.1', + ], +) diff --git a/resources/images/student-ubuntu/webssh/tests/__init__.py b/resources/images/student-ubuntu/webssh/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/resources/images/student-ubuntu/webssh/tests/data/cert.crt b/resources/images/student-ubuntu/webssh/tests/data/cert.crt new file mode 100644 index 0000000..a72be81 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/cert.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYDCCAkigAwIBAgIJAPPORA/o2Zd4MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTgxMDE0MDgwNTQzWhcNMjExMDEzMDgwNTQzWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAvSFaffq6ExFCPN4cApRopGEqVIipAYb6Ky3VHVu4pW0tOdrdKafGGYkN +GWQdsLV0AAzzxmCAPpXmmAx0m0mgtPaJp3iW8NUibkISxdEO/QJOA7y8O9iWhDdb +l9ghjwPI5AwURQkDkXbcBBBzQksYDaYseL2NGDGXkKCUQQoLzV0H+SV3vCPrbOXH +t50HKgKzEOGoT8LcI7BRCTXk1xTlK0b/4ylKUwKIsfNPH0a9RkukBjMFkpXG/2CV +VWb89+TkMzQwhcpIVn6rUCJQW5pHVRYLACP32Zki7xPUJb9OfF7XDK54v6Cwo3Fi +aZWxN6rYhnn8wRTufY3PYzv5f3XiZwIDAQABo1MwUTAdBgNVHQ4EFgQUq0kfpU/m +WQwNk3ymwm7fuVwYhJ0wHwYDVR0jBBgwFoAUq0kfpU/mWQwNk3ymwm7fuVwYhJ0w +DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAf2xudhAeOTUpNpw+ +XZWLBXBKZXINd7PrUDgEG4bB0/0kYZN+T7bMJEtmv6+9t57y6jSni9sQzpbvT2tJ +TrbZgwhDvyTm3mw5n5RpAB9ZK+lnMcasa5N4qSd6wmpXjkC+kcEs7oQ8PwgIf3xT +/aGdoswNTWCz0W8vs8yRynLB4MKx1d20IMlDkfGu5n7wXhNK0ymcT8pa6iqEYl6X +bhPVTlELl8bM/OKktFc42VXoRghLRnfl8yM/9t7HVHKfHXZrLpIdtEOvnKwtzX5r +fBMs4IPa0OIPHGCcbLGT4rIbSvSaI8yOPA93G1XXbMF1VKdKyzdGjMS6aFKfbrhV +lnaUOA== +-----END CERTIFICATE----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/cert.key b/resources/images/student-ubuntu/webssh/tests/data/cert.key new file mode 100644 index 0000000..f453068 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/cert.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC9IVp9+roTEUI8 +3hwClGikYSpUiKkBhvorLdUdW7ilbS052t0pp8YZiQ0ZZB2wtXQADPPGYIA+leaY +DHSbSaC09omneJbw1SJuQhLF0Q79Ak4DvLw72JaEN1uX2CGPA8jkDBRFCQORdtwE +EHNCSxgNpix4vY0YMZeQoJRBCgvNXQf5JXe8I+ts5ce3nQcqArMQ4ahPwtwjsFEJ +NeTXFOUrRv/jKUpTAoix808fRr1GS6QGMwWSlcb/YJVVZvz35OQzNDCFykhWfqtQ +IlBbmkdVFgsAI/fZmSLvE9Qlv058XtcMrni/oLCjcWJplbE3qtiGefzBFO59jc9j +O/l/deJnAgMBAAECggEAZSwcblvbgiuvVUQzk6W0PIrFzCa20dxUoxiHcocIRWYb +1WEhAhF/xVUtLrIBt++5N/W1yh8BO3mQuzGehxth3qwrguzdQcOiAX1S8YMeE3ZS +KWmjABiim+PJGXdCrHCH3IYhqbRitkPw+jOalJH7MgH8tDIh8hlFTNa5t/kZyybW +uGFbqF6OFmyHSDIPvjPALzSlmd5po+EywnA5oa3sObj4n5xuaFB2l/IaF3ix38vT +geo517L15cCuAa7x42i1cAGn5H/hdeO/Dw+MGk+0sXRRPooCMBzKztxpsB+7kNhk +jbsVHmTkE5UG/T7Uc0PsthZNjFwouPOrQQVUFYTnwQKBgQDwBvpmc9vX4gnADa7p +L2lgMVo6KccPFeFr4DIAYmwS0Vl0sB2j6nPVEBg3PatGLKGNMCIlcj+A3z6KQ+4o +n7pnekRwX+2+m3OPX4Rbw8c/+E0CiRPtmYp9BISKNgPoSRGsI6s/L3wzagsDsQ3v +xhKCohvfyY8JwUEPX6Hosmu/UQKBgQDJt0/ihWn0g/2uOKnXlXthxvkXFoR45sO7 +lY/yoyJB+Z4yGAjJlbyra+5xnReqYyBnf34/2AoddjT45dPCaFucMInQFINdMGF1 +NeVNzC6xa/7jjbgwf4kGqHsLC85Mrq3wyK5hwhMmfEPmRs6w+CRzM/Q78Bsr5P/T +zEa13jFINwKBgQC50L0ieUjVDKD9s9oXnWOXWz19T4BRtl+nco1i7M67lqQJCJo5 +njQD2ozUnwIrtjtuoLeeg56Ttr+krEf/3P+iQe4fjLPxXkiM0qYVoC9s311GvDXY +N4gVllzA3mYR+hcbSxW0OZ+N8ecK+ZNPbug/hx3LFi+MnrYuH5upGA7/sQKBgCRk +nlUQHP2wkqRMNNhgb9JEQ8yWk2/8snO1mDL+m7+reY8wJuW3zkJfRrXY0dw75izG +I9EA+VI3cXc2f+4jReP4HeUczlaR1AOBpc1TeVkpUuNbPlABsocw/oIPrzjGiztV ++aBJk4ruAJIbVE85ddoTFY161Gwm9MERqfBGFj4hAoGAN/ry0KC9/QkLkuPjs3uL +AU3xjBJt1SMB7KZq1yt8mBo8M4q/E3ulynBK7G3f+hS2aj7OAhU4IcPRPGqjsLO1 +dZTIOMeVyOAr0TAaioCCIyvf8hEjA7cXddnWBJYi3WiUpOc6J0uINoSlrAX2UXtw +/Aq5PmJKn4D4a75f+ue2Sw8= +-----END PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/fonts/fake-font b/resources/images/student-ubuntu/webssh/tests/data/fonts/fake-font new file mode 100644 index 0000000..e69de29 diff --git a/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example b/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example new file mode 100644 index 0000000..66ee240 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example @@ -0,0 +1 @@ +192.168.1.199 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINwZGQmNFADnAAlm5uFLQTrdxqpNxHdgg4JPbB3sR2kr diff --git a/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example2 b/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example2 new file mode 100644 index 0000000..f4c7aab --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example2 @@ -0,0 +1 @@ +192.168.1.196 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINwZGQmNFADnAAlm5uFLQTrdxqpNxHdgg4JPbB3sR2kr diff --git a/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example3 b/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example3 new file mode 100644 index 0000000..530b4ad --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/known_hosts_example3 @@ -0,0 +1 @@ +192.168.1.196 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINwZGQmNFADnAAlm5uFLQTrdxqpNxHdgg4JPbB3sR2jr diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_ed25519.key b/resources/images/student-ubuntu/webssh/tests/data/test_ed25519.key new file mode 100644 index 0000000..eb9f94c --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_ed25519.key @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACB69SvZKJh/9VgSL0G27b5xVYa8nethH3IERbi0YqJDXwAAAKhjwAdrY8AH +awAAAAtzc2gtZWQyNTUxOQAAACB69SvZKJh/9VgSL0G27b5xVYa8nethH3IERbi0YqJDXw +AAAEA9tGQi2IrprbOSbDCF+RmAHd6meNSXBUQ2ekKXm4/8xnr1K9komH/1WBIvQbbtvnFV +hryd62EfcgRFuLRiokNfAAAAI2FsZXhfZ2F5bm9yQEFsZXhzLU1hY0Jvb2stQWlyLmxvY2 +FsAQI= +-----END OPENSSH PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_ed25519_password.key b/resources/images/student-ubuntu/webssh/tests/data/test_ed25519_password.key new file mode 100644 index 0000000..d178aaa --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_ed25519_password.key @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABDaKD4ac7 +kieb+UfXaLaw68AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIOQn7fjND5ozMSV3 +CvbEtIdT73hWCMRjzS/lRdUDw50xAAAAsE8kLGyYBnl9ihJNqv378y6mO3SkzrDbWXOnK6 +ij0vnuTAvcqvWHAnyu6qBbplu/W2m55ZFeAItgaEcV2/V76sh/sAKlERqrLFyXylN0xoOW +NU5+zU08aTlbSKGmeNUU2xE/xfJq12U9XClIRuVUkUpYANxNPbmTRpVrbD3fgXMhK97Jrb +DEn8ca1IqMPiYmd/hpe5+tq3OxyRljXjCUFWTnqkp9VvUdzSTdSGZHsW9i +-----END OPENSSH PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_known_hosts b/resources/images/student-ubuntu/webssh/tests/data/test_known_hosts new file mode 100644 index 0000000..f1413d8 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_known_hosts @@ -0,0 +1 @@ +[127.0.0.1]:2222 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINwZGQmNFADnAAlm5uFLQTrdxqpNxHdgg4JPbB3sR2kr diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_new_dsa.key b/resources/images/student-ubuntu/webssh/tests/data/test_new_dsa.key new file mode 100644 index 0000000..e4d2223 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_new_dsa.key @@ -0,0 +1,21 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH +NzAAAAgQC5Y5rQ1EN+eWQUFv/9K/DLfPgjGC0mwyqvKsKyv6RLpKLc0vi0VDj8lY0WUcuG +CzdYnhIOSa9aB0buGe10gIjU2vAxkhqv1yaR+Zuj3dLDHQk6jpAAgNHciKlQSf1zho/seL +7nehYq/waXfU8/iJuXqywQgqpMLfaHOnIl/tPLGQAAABUArINMjWcrsmEgLmzf6k+sroko +5GkAAACAMQsRQjOtQGQA8/XI7vOWnEMCVntwt1Xi4RsLH5+4GpUMUcm4CvqjfFfSF4CufH +pjlywFhrAC2/ouQIpGJPGToWotk7dt5zWckGX5DscMiRVON7fxdpUMn16IO6DdUctXlWa9 +SY+NdfRESKoUCjgH5nlM8k7N2MwCK5phHHkoPu8AAACADgxrRWeNqX3gmZUM1qhrDO0mOH +oHJFrBuvJCdQ6+S1GvjuBI0rNm225+gcaAhia9k/LGk8NwCbWG1FbpesuNaNFt/FxS9LVS +qEaZoXtKuY+CUCn1BfBWF97/u0oMPwanXKIJEAhU81f5TXZM8Ui7OEIyTx1t9qgva+5/gF +cL48kAAAHoLtDYCy7Q2AsAAAAHc3NoLWRzcwAAAIEAuWOa0NRDfnlkFBb//Svwy3z4Ixgt +JsMqryrCsr+kS6Si3NL4tFQ4/JWNFlHLhgs3WJ4SDkmvWgdG7hntdICI1NrwMZIar9cmkf +mbo93Swx0JOo6QAIDR3IipUEn9c4aP7Hi+53oWKv8Gl31PP4ibl6ssEIKqTC32hzpyJf7T +yxkAAAAVAKyDTI1nK7JhIC5s3+pPrK6JKORpAAAAgDELEUIzrUBkAPP1yO7zlpxDAlZ7cL +dV4uEbCx+fuBqVDFHJuAr6o3xX0heArnx6Y5csBYawAtv6LkCKRiTxk6FqLZO3bec1nJBl ++Q7HDIkVTje38XaVDJ9eiDug3VHLV5VmvUmPjXX0REiqFAo4B+Z5TPJOzdjMAiuaYRx5KD +7vAAAAgA4Ma0Vnjal94JmVDNaoawztJjh6ByRawbryQnUOvktRr47gSNKzZttufoHGgIYm +vZPyxpPDcAm1htRW6XrLjWjRbfxcUvS1UqhGmaF7SrmPglAp9QXwVhfe/7tKDD8Gp1yiCR +AIVPNX+U12TPFIuzhCMk8dbfaoL2vuf4BXC+PJAAAAFBVcac1iVzrWVnLglRZRenUhlKLr +AAAADHNoZW5nQHNlcnZlcgECAwQFBgc= +-----END OPENSSH PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_new_rsa_password.key b/resources/images/student-ubuntu/webssh/tests/data/test_new_rsa_password.key new file mode 100644 index 0000000..68ae4c1 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_new_rsa_password.key @@ -0,0 +1,39 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +PR/8/w== +-----END OPENSSH PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_rsa.key b/resources/images/student-ubuntu/webssh/tests/data/test_rsa.key new file mode 100644 index 0000000..f50e9c5 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_rsa.key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWgIBAAKBgQDTj1bqB4WmayWNPB+8jVSYpZYk80Ujvj680pOTh2bORBjbIAyz +oWGW+GUjzKxTiiPvVmxFgx5wdsFvF03v34lEVVhMpouqPAYQ15N37K/ir5XY+9m/ +d8ufMCkjeXsQkKqFbAlQcnWMCRnOoPHS3I4vi6hmnDDeeYTSRvfLbW0fhwIBIwKB +gBIiOqZYaoqbeD9OS9z2K9KR2atlTxGxOJPXiP4ESqP3NVScWNwyZ3NXHpyrJLa0 +EbVtzsQhLn6rF+TzXnOlcipFvjsem3iYzCpuChfGQ6SovTcOjHV9z+hnpXvQ/fon +soVRZY65wKnF7IAoUwTmJS9opqgrN6kRgCd3DASAMd1bAkEA96SBVWFt/fJBNJ9H +tYnBKZGw0VeHOYmVYbvMSstssn8un+pQpUm9vlG/bp7Oxd/m+b9KWEh2xPfv6zqU +avNwHwJBANqzGZa/EpzF4J8pGti7oIAPUIDGMtfIcmqNXVMckrmzQ2vTfqtkEZsA +4rE1IERRyiJQx6EJsz21wJmGV9WJQ5kCQQDwkS0uXqVdFzgHO6S++tjmjYcxwr3g +H0CoFYSgbddOT6miqRskOQF3DZVkJT3kyuBgU2zKygz52ukQZMqxCb1fAkASvuTv +qfpH87Qq5kQhNKdbbwbmd2NxlNabazPijWuphGTdW0VfJdWfklyS2Kr+iqrs/5wV +HhathJt636Eg7oIjAkA8ht3MQ+XSl9yIJIS8gVpbPxSw5OMfw0PjVE7tBdQruiSc +nvuQES5C9BMHjF39LZiGH1iLQy7FgdHyoP+eodI7 +-----END RSA PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/test_rsa_password.key b/resources/images/student-ubuntu/webssh/tests/data/test_rsa_password.key new file mode 100644 index 0000000..7713049 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/test_rsa_password.key @@ -0,0 +1,18 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,DAA422E8A5A8EFB7 + ++nssHGmWl91IcmGiE6DdCIqGvAP04tuLh60wLjWBvdjtF9CjztPnF57xe+6pBk7o +YgF/Ry3ik9ZV9rHNcRXifDKM9crxtYlpUlkM2C0SP89sXaO0P1Q1yCnrtZUwDIKO +BNV8et5X7+AGMFsy/nmv0NFMrbpoG03Dppsloecd29NTRlIXwxHRFyHxy6BdEib/ +Dn0mEVbwg3dTvKrd/sODWR9hRwpDGM9nkEbUNJCh7vMwFKkIZZF8yqFvmGckuO5C +HZkDJ6RkEDYrSZJAavQaiOPF5bu3cHughRfnrIKVrQuTTDiWjwX9Ny8e4p4k7dy7 +rLpbPhtxUOUbpOF7T1QxljDi1Tcq3Ebk3kN/ZLPRFnDrJfyUx+m9BXmAa78Wxs/l +KaS8DTkYykd3+EGOeJFjZg2bvgqil4V+5JIt/+MQ5pZ/ui7i4GcH2bvZyGAbrXzP +3LipSAdN5RG+fViLe3HUtfCx4ZAgtU78TWJrLk2FwKQGglFxKLnswp+IKZb09rZV +uxmG4pPLUnH+mMYdiy5ugzj+5C8iZ0/IstpHVmO6GWROfedpJ82eMztTOtdhfMep +8Z3HwAwkDtksL7Gq9klb0Wq5+uRlBWetixddAvnmqXNzYhaANWcAF/2a2Hz06Rb0 +e6pe/g0Ek5KV+6YI+D+oEblG0Sr+d4NtxtDTmIJKNVkmzlhI2s53bHp6txCb5JWJ +S8mKLPBBBzaNXYd3odDvGXguuxUntWSsD11KyR6B9DXMIfWQW5dT7hp5kTMGlXWJ +lD2hYab13DCCuAkwVTdpzhHYLZyxLYoSu05W6z8SAOs= +-----END RSA PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/data/user_rsa_key b/resources/images/student-ubuntu/webssh/tests/data/user_rsa_key new file mode 100644 index 0000000..ee64f23 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/data/user_rsa_key @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDI7iK3d8eWYZlYloat94c5VjtFY7c/0zuGl8C7uMnZ3t6i2G99 +66hEW0nCFSZkOW5F0XKEVj+EUCHvo8koYC6wiohAqWQnEwIoOoh7GSAcB8gP/qaq ++adIl/Rvlby/mHakj+y05LBND6nFWHAn1y1gOFFKUXSJNRZPXSFy47gqzwIBIwKB +gQCbANjz7q/pCXZLp1Hz6tYHqOvlEmjK1iabB1oqafrMpJ0eibUX/u+FMHq6StR5 +M5413BaDWHokPdEJUnabfWXXR3SMlBUKrck0eAer1O8m78yxu3OEdpRk+znVo4DL +guMeCdJB/qcF0kEsx+Q8HP42MZU1oCmk3PbfXNFwaHbWuwJBAOQ/ry/hLD7AqB8x +DmCM82A9E59ICNNlHOhxpJoh6nrNTPCsBAEu/SmqrL8mS6gmbRKUaya5Lx1pkxj2 +s/kWOokCQQDhXCcYXjjWiIfxhl6Rlgkk1vmI0l6785XSJNv4P7pXjGmShXfIzroh +S8uWK3tL0GELY7+UAKDTUEVjjQdGxYSXAkEA3bo1JzKCwJ3lJZ1ebGuqmADRO6UP +40xH977aadfN1mEI6cusHmgpISl0nG5YH7BMsvaT+bs1FUH8m+hXDzoqOwJBAK3Z +X/za+KV/REya2z0b+GzgWhkXUGUa/owrEBdHGriQ47osclkUgPUdNqcLmaDilAF4 +1Z4PHPrI5RJIONAx+JECQQC/fChqjBgFpk6iJ+BOdSexQpgfxH/u/457W10Y43HR +soS+8btbHqjQkowQ/2NTlUfWvqIlfxs6ZbFsIp/HrhZL +-----END RSA PRIVATE KEY----- diff --git a/resources/images/student-ubuntu/webssh/tests/sshserver.py b/resources/images/student-ubuntu/webssh/tests/sshserver.py new file mode 100644 index 0000000..1385a98 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/sshserver.py @@ -0,0 +1,213 @@ +import base64 +import random +import socket +# import sys +import threading +# import traceback +import paramiko + +from binascii import hexlify +from tests.utils import make_tests_data_path + + +# setup logging +paramiko.util.log_to_file(make_tests_data_path('sshserver.log')) + +host_key = paramiko.RSAKey(filename=make_tests_data_path('test_rsa.key')) +# host_key = paramiko.DSSKey(filename='test_dss.key') + +print('Read key: ' + hexlify(host_key.get_fingerprint()).decode('utf-8')) + +banner = u'\r\n\u6b22\u8fce\r\n' +event_timeout = 5 + + +class Server(paramiko.ServerInterface): + # 'data' is the output of base64.b64encode(key) + # (using the "user_rsa_key" files) + data = (b'AAAAB3NzaC1yc2EAAAABIwAAAIEAyO4it3fHlmGZWJaGrfeHOVY7RWO3P9M7hp' + b'fAu7jJ2d7eothvfeuoRFtJwhUmZDluRdFyhFY/hFAh76PJKGAusIqIQKlkJxMC' + b'KDqIexkgHAfID/6mqvmnSJf0b5W8v5h2pI/stOSwTQ+pxVhwJ9ctYDhRSlF0iT' + b'UWT10hcuO4Ks8=') + good_pub_key = paramiko.RSAKey(data=base64.decodebytes(data)) + + commands = [ + b'$SHELL -ilc "locale charmap"', + b'$SHELL -ic "locale charmap"' + ] + encodings = ['UTF-8', 'GBK', 'UTF-8\r\n', 'GBK\r\n'] + + def __init__(self, encodings=[]): + self.shell_event = threading.Event() + self.exec_event = threading.Event() + self.cmd_to_enc = self.get_cmd2enc(encodings) + self.password_verified = False + self.key_verified = False + + def get_cmd2enc(self, encodings): + n = len(self.commands) + while len(encodings) < n: + encodings.append(random.choice(self.encodings)) + return dict(zip(self.commands, encodings[0:n])) + + def check_channel_request(self, kind, chanid): + if kind == 'session': + return paramiko.OPEN_SUCCEEDED + return paramiko.OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED + + def check_auth_password(self, username, password): + print('Auth attempt with username: {!r} & password: {!r}'.format(username, password)) # noqa + if (username in ['robey', 'bar', 'foo']) and (password == 'foo'): + return paramiko.AUTH_SUCCESSFUL + return paramiko.AUTH_FAILED + + def check_auth_publickey(self, username, key): + print('Auth attempt with username: {!r} & key: {!r}'.format(username, hexlify(key.get_fingerprint()).decode('utf-8'))) # noqa + if (username in ['robey', 'keyonly']) and (key == self.good_pub_key): + return paramiko.AUTH_SUCCESSFUL + if username == 'pkey2fa' and key == self.good_pub_key: + self.key_verified = True + return paramiko.AUTH_PARTIALLY_SUCCESSFUL + return paramiko.AUTH_FAILED + + def check_auth_interactive(self, username, submethods): + if username in ['pass2fa', 'pkey2fa']: + self.username = username + prompt = 'Verification code: ' if self.password_verified else 'Password: ' # noqa + print(username, prompt) + return paramiko.InteractiveQuery('', '', prompt) + return paramiko.AUTH_FAILED + + def check_auth_interactive_response(self, responses): + if self.username in ['pass2fa', 'pkey2fa']: + if not self.password_verified: + if responses[0] == 'password': + print('password verified') + self.password_verified = True + if self.username == 'pkey2fa': + return self.check_auth_interactive(self.username, '') + else: + print('wrong password: {}'.format(responses[0])) + return paramiko.AUTH_FAILED + else: + if responses[0] == 'passcode': + print('totp verified') + return paramiko.AUTH_SUCCESSFUL + else: + print('wrong totp: {}'.format(responses[0])) + return paramiko.AUTH_FAILED + else: + return paramiko.AUTH_FAILED + + def get_allowed_auths(self, username): + if username == 'keyonly': + return 'publickey' + if username == 'pass2fa': + return 'keyboard-interactive' + if username == 'pkey2fa': + if not self.key_verified: + return 'publickey' + else: + return 'keyboard-interactive' + return 'password,publickey' + + def check_channel_exec_request(self, channel, command): + if command not in self.commands: + ret = False + else: + ret = True + self.encoding = self.cmd_to_enc[command] + channel.send(self.encoding) + channel.shutdown(1) + self.exec_event.set() + return ret + + def check_channel_shell_request(self, channel): + self.shell_event.set() + return True + + def check_channel_pty_request(self, channel, term, width, height, + pixelwidth, pixelheight, modes): + return True + + def check_channel_window_change_request(self, channel, width, height, + pixelwidth, pixelheight): + channel.send('resized') + return True + + +def run_ssh_server(port=2200, running=True, encodings=[]): + # now connect + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind(('127.0.0.1', port)) + sock.listen(100) + + while running: + client, addr = sock.accept() + print('Got a connection!') + + t = paramiko.Transport(client) + t.load_server_moduli() + t.add_server_key(host_key) + server = Server(encodings) + try: + t.start_server(server=server) + except Exception as e: + print(e) + continue + + # wait for auth + chan = t.accept(2) + if chan is None: + print('*** No channel.') + continue + + username = t.get_username() + print('{} Authenticated!'.format(username)) + + server.shell_event.wait(timeout=event_timeout) + if not server.shell_event.is_set(): + print('*** Client never asked for a shell.') + continue + + server.exec_event.wait(timeout=event_timeout) + if not server.exec_event.is_set(): + print('*** Client never asked for a command.') + continue + + # chan.send('\r\n\r\nWelcome!\r\n\r\n') + print(server.encoding) + try: + banner_encoded = banner.encode(server.encoding) + except (ValueError, LookupError): + continue + + chan.send(banner_encoded) + if username == 'bar': + msg = chan.recv(1024) + chan.send(msg) + elif username == 'foo': + lst = [] + while True: + msg = chan.recv(32 * 1024) + lst.append(msg) + if msg.endswith(b'\r\n\r\n'): + break + data = b''.join(lst) + while data: + s = chan.send(data) + data = data[s:] + else: + chan.close() + t.close() + client.close() + + try: + sock.close() + except Exception: + pass + + +if __name__ == '__main__': + run_ssh_server() diff --git a/resources/images/student-ubuntu/webssh/tests/test_app.py b/resources/images/student-ubuntu/webssh/tests/test_app.py new file mode 100644 index 0000000..bd31b5f --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/test_app.py @@ -0,0 +1,792 @@ +import json +import random +import threading +import tornado.websocket +import tornado.gen + +from tornado.testing import AsyncHTTPTestCase +from tornado.httpclient import HTTPError +from tornado.options import options +from tests.sshserver import run_ssh_server, banner, Server +from tests.utils import encode_multipart_formdata, read_file, make_tests_data_path # noqa +from webssh import handler +from webssh.main import make_app, make_handlers +from webssh.settings import ( + get_app_settings, get_server_settings, max_body_size +) +from webssh.utils import to_str +from webssh.worker import clients + +try: + from urllib.parse import urlencode +except ImportError: + from urllib import urlencode + + +swallow_http_errors = handler.swallow_http_errors +server_encodings = {e.strip() for e in Server.encodings} + + +class TestAppBase(AsyncHTTPTestCase): + + def get_httpserver_options(self): + return get_server_settings(options) + + def assert_response(self, bstr, response): + if swallow_http_errors: + self.assertEqual(response.code, 200) + self.assertIn(bstr, response.body) + else: + self.assertEqual(response.code, 400) + self.assertIn(b'Bad Request', response.body) + + def assert_status_in(self, status, data): + self.assertIsNone(data['encoding']) + self.assertIsNone(data['id']) + self.assertIn(status, data['status']) + + def assert_status_equal(self, status, data): + self.assertIsNone(data['encoding']) + self.assertIsNone(data['id']) + self.assertEqual(status, data['status']) + + def assert_status_none(self, data): + self.assertIsNotNone(data['encoding']) + self.assertIsNotNone(data['id']) + self.assertIsNone(data['status']) + + def fetch_request(self, url, method='GET', body='', headers={}, sync=True): + if not sync and url.startswith('/'): + url = self.get_url(url) + + if isinstance(body, dict): + body = urlencode(body) + + if not headers: + headers = self.headers + else: + headers.update(self.headers) + + client = self if sync else self.get_http_client() + return client.fetch(url, method=method, body=body, headers=headers) + + def sync_post(self, url, body, headers={}): + return self.fetch_request(url, 'POST', body, headers) + + def async_post(self, url, body, headers={}): + return self.fetch_request(url, 'POST', body, headers, sync=False) + + +class TestAppBasic(TestAppBase): + + running = [True] + sshserver_port = 2200 + body = 'hostname=127.0.0.1&port={}&_xsrf=yummy&username=robey&password=foo'.format(sshserver_port) # noqa + headers = {'Cookie': '_xsrf=yummy'} + + def get_app(self): + self.body_dict = { + 'hostname': '127.0.0.1', + 'port': str(self.sshserver_port), + 'username': 'robey', + 'password': '', + '_xsrf': 'yummy' + } + loop = self.io_loop + options.debug = False + options.policy = random.choice(['warning', 'autoadd']) + options.hostfile = '' + options.syshostfile = '' + options.tdstream = '' + options.delay = 0.1 + app = make_app(make_handlers(loop, options), get_app_settings(options)) + return app + + @classmethod + def setUpClass(cls): + print('='*20) + t = threading.Thread( + target=run_ssh_server, args=(cls.sshserver_port, cls.running) + ) + t.setDaemon(True) + t.start() + + @classmethod + def tearDownClass(cls): + cls.running.pop() + print('='*20) + + def test_app_with_invalid_form_for_missing_argument(self): + response = self.fetch('/') + self.assertEqual(response.code, 200) + + body = 'port=7000&username=admin&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Missing argument hostname', response) + + body = 'hostname=127.0.0.1&port=7000&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Missing argument username', response) + + body = 'hostname=&port=&username=&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Missing value hostname', response) + + body = 'hostname=127.0.0.1&port=7000&username=&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Missing value username', response) + + def test_app_with_invalid_form_for_invalid_value(self): + body = 'hostname=127.0.0&port=22&username=&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Invalid hostname', response) + + body = 'hostname=http://www.googe.com&port=22&username=&password&_xsrf=yummy' # noqa + response = self.sync_post('/', body) + self.assert_response(b'Invalid hostname', response) + + body = 'hostname=127.0.0.1&port=port&username=&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Invalid port', response) + + body = 'hostname=127.0.0.1&port=70000&username=&password&_xsrf=yummy' + response = self.sync_post('/', body) + self.assert_response(b'Invalid port', response) + + def test_app_with_wrong_hostname_ip(self): + body = 'hostname=127.0.0.2&port=2200&username=admin&_xsrf=yummy' + response = self.sync_post('/', body) + self.assertEqual(response.code, 200) + self.assertIn(b'Unable to connect to', response.body) + + def test_app_with_wrong_hostname_domain(self): + body = 'hostname=xxxxxxxxxxxx&port=2200&username=admin&_xsrf=yummy' + response = self.sync_post('/', body) + self.assertEqual(response.code, 200) + self.assertIn(b'Unable to connect to', response.body) + + def test_app_with_wrong_port(self): + body = 'hostname=127.0.0.1&port=7000&username=admin&_xsrf=yummy' + response = self.sync_post('/', body) + self.assertEqual(response.code, 200) + self.assertIn(b'Unable to connect to', response.body) + + def test_app_with_wrong_credentials(self): + response = self.sync_post('/', self.body + 's') + self.assert_status_in('Authentication failed.', json.loads(to_str(response.body))) # noqa + + def test_app_with_correct_credentials(self): + response = self.sync_post('/', self.body) + self.assert_status_none(json.loads(to_str(response.body))) + + def test_app_with_correct_credentials_but_with_no_port(self): + default_port = handler.DEFAULT_PORT + handler.DEFAULT_PORT = self.sshserver_port + + # with no port value + body = self.body.replace(str(self.sshserver_port), '') + response = self.sync_post('/', body) + self.assert_status_none(json.loads(to_str(response.body))) + + # with no port argument + body = body.replace('port=&', '') + response = self.sync_post('/', body) + self.assert_status_none(json.loads(to_str(response.body))) + + handler.DEFAULT_PORT = default_port + + @tornado.testing.gen_test + def test_app_with_correct_credentials_timeout(self): + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + yield tornado.gen.sleep(options.delay + 0.1) + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertIsNone(msg) + self.assertEqual(ws.close_reason, 'Websocket authentication failed.') + + @tornado.testing.gen_test + def test_app_with_correct_credentials_but_ip_not_matched(self): + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + clients = handler.clients + handler.clients = {} + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertIsNone(msg) + self.assertEqual(ws.close_reason, 'Websocket authentication failed.') + handler.clients = clients + + @tornado.testing.gen_test + def test_app_with_correct_credentials_user_robey(self): + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertEqual(to_str(msg, data['encoding']), banner) + ws.close() + + @tornado.testing.gen_test + def test_app_with_correct_credentials_but_without_id_argument(self): + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws' + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertIsNone(msg) + self.assertIn('Missing argument id', ws.close_reason) + + @tornado.testing.gen_test + def test_app_with_correct_credentials_but_empty_id(self): + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertIsNone(msg) + self.assertIn('Missing value id', ws.close_reason) + + @tornado.testing.gen_test + def test_app_with_correct_credentials_but_wrong_id(self): + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=1' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertIsNone(msg) + self.assertIn('Websocket authentication failed', ws.close_reason) + + @tornado.testing.gen_test + def test_app_with_correct_credentials_user_bar(self): + body = self.body.replace('robey', 'bar') + url = self.get_url('/') + response = yield self.async_post(url, body) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertEqual(to_str(msg, data['encoding']), banner) + + # messages below will be ignored silently + yield ws.write_message('hello') + yield ws.write_message('"hello"') + yield ws.write_message('[hello]') + yield ws.write_message(json.dumps({'resize': []})) + yield ws.write_message(json.dumps({'resize': {}})) + yield ws.write_message(json.dumps({'resize': 'ab'})) + yield ws.write_message(json.dumps({'resize': ['a', 'b']})) + yield ws.write_message(json.dumps({'resize': {'a': 1, 'b': 2}})) + yield ws.write_message(json.dumps({'resize': [100]})) + yield ws.write_message(json.dumps({'resize': [100]*10})) + yield ws.write_message(json.dumps({'resize': [-1, -1]})) + yield ws.write_message(json.dumps({'data': [1]})) + yield ws.write_message(json.dumps({'data': (1,)})) + yield ws.write_message(json.dumps({'data': {'a': 2}})) + yield ws.write_message(json.dumps({'data': 1})) + yield ws.write_message(json.dumps({'data': 2.1})) + yield ws.write_message(json.dumps({'key-non-existed': 'hello'})) + # end - those just for testing webssh websocket stablity + + yield ws.write_message(json.dumps({'resize': [79, 23]})) + msg = yield ws.read_message() + self.assertEqual(b'resized', msg) + + yield ws.write_message(json.dumps({'data': 'bye'})) + msg = yield ws.read_message() + self.assertEqual(b'bye', msg) + ws.close() + + @tornado.testing.gen_test + def test_app_auth_with_valid_pubkey_by_urlencoded_form(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + self.body_dict.update(privatekey=privatekey) + response = yield self.async_post(url, self.body_dict) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertEqual(to_str(msg, data['encoding']), banner) + ws.close() + + @tornado.testing.gen_test + def test_app_auth_with_valid_pubkey_by_multipart_form(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + files = [('privatekey', 'user_rsa_key', privatekey)] + content_type, body = encode_multipart_formdata(self.body_dict.items(), + files) + headers = { + 'Content-Type': content_type, 'content-length': str(len(body)) + } + response = yield self.async_post(url, body, headers=headers) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertEqual(to_str(msg, data['encoding']), banner) + ws.close() + + @tornado.testing.gen_test + def test_app_auth_with_invalid_pubkey_for_user_robey(self): + url = self.get_url('/') + privatekey = 'h' * 1024 + files = [('privatekey', 'user_rsa_key', privatekey)] + content_type, body = encode_multipart_formdata(self.body_dict.items(), + files) + headers = { + 'Content-Type': content_type, 'content-length': str(len(body)) + } + + if swallow_http_errors: + response = yield self.async_post(url, body, headers=headers) + self.assertIn(b'Invalid key', response.body) + else: + with self.assertRaises(HTTPError) as ctx: + yield self.async_post(url, body, headers=headers) + self.assertIn('Bad Request', ctx.exception.message) + + @tornado.testing.gen_test + def test_app_auth_with_pubkey_exceeds_key_max_size(self): + url = self.get_url('/') + privatekey = 'h' * (handler.PrivateKey.max_length + 1) + files = [('privatekey', 'user_rsa_key', privatekey)] + content_type, body = encode_multipart_formdata(self.body_dict.items(), + files) + headers = { + 'Content-Type': content_type, 'content-length': str(len(body)) + } + if swallow_http_errors: + response = yield self.async_post(url, body, headers=headers) + self.assertIn(b'Invalid key', response.body) + else: + with self.assertRaises(HTTPError) as ctx: + yield self.async_post(url, body, headers=headers) + self.assertIn('Bad Request', ctx.exception.message) + + @tornado.testing.gen_test + def test_app_auth_with_pubkey_cannot_be_decoded_by_multipart_form(self): + url = self.get_url('/') + privatekey = 'h' * 1024 + files = [('privatekey', 'user_rsa_key', privatekey)] + content_type, body = encode_multipart_formdata(self.body_dict.items(), + files) + body = body.encode('utf-8') + # added some gbk bytes to the privatekey, make it cannot be decoded + body = body[:-100] + b'\xb4\xed\xce\xf3' + body[-100:] + headers = { + 'Content-Type': content_type, 'content-length': str(len(body)) + } + if swallow_http_errors: + response = yield self.async_post(url, body, headers=headers) + self.assertIn(b'Invalid unicode', response.body) + else: + with self.assertRaises(HTTPError) as ctx: + yield self.async_post(url, body, headers=headers) + self.assertIn('Bad Request', ctx.exception.message) + + def test_app_post_form_with_large_body_size_by_multipart_form(self): + privatekey = 'h' * (2 * max_body_size) + files = [('privatekey', 'user_rsa_key', privatekey)] + content_type, body = encode_multipart_formdata(self.body_dict.items(), + files) + headers = { + 'Content-Type': content_type, 'content-length': str(len(body)) + } + response = self.sync_post('/', body, headers=headers) + self.assertIn(response.code, [400, 599]) + + def test_app_post_form_with_large_body_size_by_urlencoded_form(self): + privatekey = 'h' * (2 * max_body_size) + body = self.body + '&privatekey=' + privatekey + response = self.sync_post('/', body) + self.assertIn(response.code, [400, 599]) + + @tornado.testing.gen_test + def test_app_with_user_keyonly_for_bad_authentication_type(self): + self.body_dict.update(username='keyonly', password='foo') + response = yield self.async_post('/', self.body_dict) + self.assertEqual(response.code, 200) + self.assert_status_in('Bad authentication type', json.loads(to_str(response.body))) # noqa + + @tornado.testing.gen_test + def test_app_with_user_pass2fa_with_correct_passwords(self): + self.body_dict.update(username='pass2fa', password='password', + totp='passcode') + response = yield self.async_post('/', self.body_dict) + self.assertEqual(response.code, 200) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + @tornado.testing.gen_test + def test_app_with_user_pass2fa_with_wrong_pkey_correct_passwords(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + self.body_dict.update(username='pass2fa', password='password', + privatekey=privatekey, totp='passcode') + response = yield self.async_post(url, self.body_dict) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + @tornado.testing.gen_test + def test_app_with_user_pkey2fa_with_correct_passwords(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + self.body_dict.update(username='pkey2fa', password='password', + privatekey=privatekey, totp='passcode') + response = yield self.async_post(url, self.body_dict) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + @tornado.testing.gen_test + def test_app_with_user_pkey2fa_with_wrong_password(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + self.body_dict.update(username='pkey2fa', password='wrongpassword', + privatekey=privatekey, totp='passcode') + response = yield self.async_post(url, self.body_dict) + data = json.loads(to_str(response.body)) + self.assert_status_in('Authentication failed', data) + + @tornado.testing.gen_test + def test_app_with_user_pkey2fa_with_wrong_passcode(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + self.body_dict.update(username='pkey2fa', password='password', + privatekey=privatekey, totp='wrongpasscode') + response = yield self.async_post(url, self.body_dict) + data = json.loads(to_str(response.body)) + self.assert_status_in('Authentication failed', data) + + @tornado.testing.gen_test + def test_app_with_user_pkey2fa_with_empty_passcode(self): + url = self.get_url('/') + privatekey = read_file(make_tests_data_path('user_rsa_key')) + self.body_dict.update(username='pkey2fa', password='password', + privatekey=privatekey, totp='') + response = yield self.async_post(url, self.body_dict) + data = json.loads(to_str(response.body)) + self.assert_status_in('Need a verification code', data) + + +class OtherTestBase(TestAppBase): + sshserver_port = 3300 + headers = {'Cookie': '_xsrf=yummy'} + debug = False + policy = None + xsrf = True + hostfile = '' + syshostfile = '' + tdstream = '' + maxconn = 20 + origin = 'same' + encodings = [] + body = { + 'hostname': '127.0.0.1', + 'port': '', + 'username': 'robey', + 'password': 'foo', + '_xsrf': 'yummy' + } + + def get_app(self): + self.body.update(port=str(self.sshserver_port)) + loop = self.io_loop + options.debug = self.debug + options.xsrf = self.xsrf + options.policy = self.policy if self.policy else random.choice(['warning', 'autoadd']) # noqa + options.hostfile = self.hostfile + options.syshostfile = self.syshostfile + options.tdstream = self.tdstream + options.maxconn = self.maxconn + options.origin = self.origin + app = make_app(make_handlers(loop, options), get_app_settings(options)) + return app + + def setUp(self): + print('='*20) + self.running = True + OtherTestBase.sshserver_port += 1 + + t = threading.Thread( + target=run_ssh_server, + args=(self.sshserver_port, self.running, self.encodings) + ) + t.setDaemon(True) + t.start() + super(OtherTestBase, self).setUp() + + def tearDown(self): + self.running = False + print('='*20) + super(OtherTestBase, self).tearDown() + + +class TestAppInDebugMode(OtherTestBase): + + debug = True + + def assert_response(self, bstr, response): + if swallow_http_errors: + self.assertEqual(response.code, 200) + self.assertIn(bstr, response.body) + else: + self.assertEqual(response.code, 500) + self.assertIn(b'Uncaught exception', response.body) + + def test_server_error_for_post_method(self): + body = dict(self.body, error='raise') + response = self.sync_post('/', body) + self.assert_response(b'"status": "Internal Server Error"', response) + + def test_html(self): + response = self.fetch('/', method='GET') + self.assertIn(b'novalidate>', response.body) + + +class TestAppWithLargeBuffer(OtherTestBase): + + @tornado.testing.gen_test + def test_app_for_sending_message_with_large_size(self): + url = self.get_url('/') + response = yield self.async_post(url, dict(self.body, username='foo')) + data = json.loads(to_str(response.body)) + self.assert_status_none(data) + + url = url.replace('http', 'ws') + ws_url = url + 'ws?id=' + data['id'] + ws = yield tornado.websocket.websocket_connect(ws_url) + msg = yield ws.read_message() + self.assertEqual(to_str(msg, data['encoding']), banner) + + send = 'h' * (64 * 1024) + '\r\n\r\n' + yield ws.write_message(json.dumps({'data': send})) + lst = [] + while True: + msg = yield ws.read_message() + lst.append(msg) + if msg.endswith(b'\r\n\r\n'): + break + recv = b''.join(lst).decode(data['encoding']) + self.assertEqual(send, recv) + ws.close() + + +class TestAppWithRejectPolicy(OtherTestBase): + + policy = 'reject' + hostfile = make_tests_data_path('known_hosts_example') + + @tornado.testing.gen_test + def test_app_with_hostname_not_in_hostkeys(self): + response = yield self.async_post('/', self.body) + data = json.loads(to_str(response.body)) + message = 'Connection to {}:{} is not allowed.'.format(self.body['hostname'], self.sshserver_port) # noqa + self.assertEqual(message, data['status']) + + +class TestAppWithBadHostKey(OtherTestBase): + + policy = random.choice(['warning', 'autoadd', 'reject']) + hostfile = make_tests_data_path('test_known_hosts') + + def setUp(self): + self.sshserver_port = 2222 + super(TestAppWithBadHostKey, self).setUp() + + @tornado.testing.gen_test + def test_app_with_bad_host_key(self): + response = yield self.async_post('/', self.body) + data = json.loads(to_str(response.body)) + self.assertEqual('Bad host key.', data['status']) + + +class TestAppWithTrustedStream(OtherTestBase): + tdstream = '127.0.0.2' + + def test_with_forbidden_get_request(self): + response = self.fetch('/', method='GET') + self.assertEqual(response.code, 403) + self.assertIn('Forbidden', response.error.message) + + def test_with_forbidden_post_request(self): + response = self.sync_post('/', self.body) + self.assertEqual(response.code, 403) + self.assertIn('Forbidden', response.error.message) + + def test_with_forbidden_put_request(self): + response = self.fetch_request('/', method='PUT', body=self.body) + self.assertEqual(response.code, 403) + self.assertIn('Forbidden', response.error.message) + + +class TestAppNotFoundHandler(OtherTestBase): + + custom_headers = handler.MixinHandler.custom_headers + + def test_with_not_found_get_request(self): + response = self.fetch('/pathnotfound', method='GET') + self.assertEqual(response.code, 404) + self.assertEqual( + response.headers['Server'], self.custom_headers['Server'] + ) + self.assertIn(b'404: Not Found', response.body) + + def test_with_not_found_post_request(self): + response = self.sync_post('/pathnotfound', self.body) + self.assertEqual(response.code, 404) + self.assertEqual( + response.headers['Server'], self.custom_headers['Server'] + ) + self.assertIn(b'404: Not Found', response.body) + + def test_with_not_found_put_request(self): + response = self.fetch_request('/pathnotfound', method='PUT', + body=self.body) + self.assertEqual(response.code, 404) + self.assertEqual( + response.headers['Server'], self.custom_headers['Server'] + ) + self.assertIn(b'404: Not Found', response.body) + + +class TestAppWithHeadRequest(OtherTestBase): + + def test_with_index_path(self): + response = self.fetch('/', method='HEAD') + self.assertEqual(response.code, 200) + + def test_with_ws_path(self): + response = self.fetch('/ws', method='HEAD') + self.assertEqual(response.code, 405) + + def test_with_not_found_path(self): + response = self.fetch('/notfound', method='HEAD') + self.assertEqual(response.code, 404) + + +class TestAppWithPutRequest(OtherTestBase): + + xsrf = False + + @tornado.testing.gen_test + def test_app_with_method_not_supported(self): + with self.assertRaises(HTTPError) as ctx: + yield self.fetch_request('/', 'PUT', self.body, sync=False) + self.assertIn('Method Not Allowed', ctx.exception.message) + + +class TestAppWithTooManyConnections(OtherTestBase): + + maxconn = 1 + + def setUp(self): + clients.clear() + super(TestAppWithTooManyConnections, self).setUp() + + @tornado.testing.gen_test + def test_app_with_too_many_connections(self): + clients['127.0.0.1'] = {'fake_worker_id': None} + + url = self.get_url('/') + response = yield self.async_post(url, self.body) + data = json.loads(to_str(response.body)) + self.assertEqual('Too many live connections.', data['status']) + + clients['127.0.0.1'].clear() + response = yield self.async_post(url, self.body) + self.assert_status_none(json.loads(to_str(response.body))) + + +class TestAppWithCrossOriginOperation(OtherTestBase): + + origin = 'http://www.example.com' + + @tornado.testing.gen_test + def test_app_with_wrong_event_origin(self): + body = dict(self.body, _origin='localhost') + response = yield self.async_post('/', body) + self.assert_status_equal('Cross origin operation is not allowed.', json.loads(to_str(response.body))) # noqa + + @tornado.testing.gen_test + def test_app_with_wrong_header_origin(self): + headers = dict(Origin='localhost') + response = yield self.async_post('/', self.body, headers=headers) + self.assert_status_equal('Cross origin operation is not allowed.', json.loads(to_str(response.body)), ) # noqa + + @tornado.testing.gen_test + def test_app_with_correct_event_origin(self): + body = dict(self.body, _origin=self.origin) + response = yield self.async_post('/', body) + self.assert_status_none(json.loads(to_str(response.body))) + self.assertIsNone(response.headers.get('Access-Control-Allow-Origin')) + + @tornado.testing.gen_test + def test_app_with_correct_header_origin(self): + headers = dict(Origin=self.origin) + response = yield self.async_post('/', self.body, headers=headers) + self.assert_status_none(json.loads(to_str(response.body))) + self.assertEqual( + response.headers.get('Access-Control-Allow-Origin'), self.origin + ) + + +class TestAppWithBadEncoding(OtherTestBase): + + encodings = [u'\u7f16\u7801'] + + @tornado.testing.gen_test + def test_app_with_a_bad_encoding(self): + response = yield self.async_post('/', self.body) + dic = json.loads(to_str(response.body)) + self.assert_status_none(dic) + self.assertIn(dic['encoding'], server_encodings) + + +class TestAppWithUnknownEncoding(OtherTestBase): + + encodings = [u'\u7f16\u7801', u'UnknownEncoding'] + + @tornado.testing.gen_test + def test_app_with_a_unknown_encoding(self): + response = yield self.async_post('/', self.body) + self.assert_status_none(json.loads(to_str(response.body))) + dic = json.loads(to_str(response.body)) + self.assert_status_none(dic) + self.assertEqual(dic['encoding'], 'utf-8') diff --git a/resources/images/student-ubuntu/webssh/tests/test_handler.py b/resources/images/student-ubuntu/webssh/tests/test_handler.py new file mode 100644 index 0000000..2f30d9d --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/test_handler.py @@ -0,0 +1,317 @@ +import unittest +import paramiko + +from tornado.httputil import HTTPServerRequest +from tornado.options import options +from tests.utils import read_file, make_tests_data_path +from webssh import handler +from webssh import worker +from webssh.handler import ( + MixinHandler, WsockHandler, PrivateKey, InvalidValueError +) + +try: + from unittest.mock import Mock +except ImportError: + from mock import Mock + + +class TestMixinHandler(unittest.TestCase): + + def test_is_forbidden(self): + mhandler = MixinHandler() + handler.redirecting = True + options.fbidhttp = True + + context = Mock( + address=('8.8.8.8', 8888), + trusted_downstream=['127.0.0.1'], + _orig_protocol='http' + ) + hostname = '4.4.4.4' + self.assertTrue(mhandler.is_forbidden(context, hostname)) + + context = Mock( + address=('8.8.8.8', 8888), + trusted_downstream=[], + _orig_protocol='http' + ) + hostname = 'www.google.com' + self.assertEqual(mhandler.is_forbidden(context, hostname), False) + + context = Mock( + address=('8.8.8.8', 8888), + trusted_downstream=[], + _orig_protocol='http' + ) + hostname = '4.4.4.4' + self.assertTrue(mhandler.is_forbidden(context, hostname)) + + context = Mock( + address=('192.168.1.1', 8888), + trusted_downstream=[], + _orig_protocol='http' + ) + hostname = 'www.google.com' + self.assertIsNone(mhandler.is_forbidden(context, hostname)) + + options.fbidhttp = False + self.assertIsNone(mhandler.is_forbidden(context, hostname)) + + hostname = '4.4.4.4' + self.assertIsNone(mhandler.is_forbidden(context, hostname)) + + handler.redirecting = False + self.assertIsNone(mhandler.is_forbidden(context, hostname)) + + context._orig_protocol = 'https' + self.assertIsNone(mhandler.is_forbidden(context, hostname)) + + def test_get_redirect_url(self): + mhandler = MixinHandler() + hostname = 'www.example.com' + uri = '/' + port = 443 + + self.assertEqual( + mhandler.get_redirect_url(hostname, port, uri=uri), + 'https://www.example.com/' + ) + + port = 4433 + self.assertEqual( + mhandler.get_redirect_url(hostname, port, uri), + 'https://www.example.com:4433/' + ) + + def test_get_client_addr(self): + mhandler = MixinHandler() + client_addr = ('8.8.8.8', 8888) + context_addr = ('127.0.0.1', 1234) + options.xheaders = True + + mhandler.context = Mock(address=context_addr) + mhandler.get_real_client_addr = lambda: None + self.assertEqual(mhandler.get_client_addr(), context_addr) + + mhandler.context = Mock(address=context_addr) + mhandler.get_real_client_addr = lambda: client_addr + self.assertEqual(mhandler.get_client_addr(), client_addr) + + options.xheaders = False + mhandler.context = Mock(address=context_addr) + mhandler.get_real_client_addr = lambda: client_addr + self.assertEqual(mhandler.get_client_addr(), context_addr) + + def test_get_real_client_addr(self): + x_forwarded_for = '1.1.1.1' + x_forwarded_port = 1111 + x_real_ip = '2.2.2.2' + x_real_port = 2222 + fake_port = 65535 + + mhandler = MixinHandler() + mhandler.request = HTTPServerRequest(uri='/') + mhandler.request.remote_ip = x_forwarded_for + + self.assertIsNone(mhandler.get_real_client_addr()) + + mhandler.request.headers.add('X-Forwarded-For', x_forwarded_for) + self.assertEqual(mhandler.get_real_client_addr(), + (x_forwarded_for, fake_port)) + + mhandler.request.headers.add('X-Forwarded-Port', fake_port + 1) + self.assertEqual(mhandler.get_real_client_addr(), + (x_forwarded_for, fake_port)) + + mhandler.request.headers['X-Forwarded-Port'] = x_forwarded_port + self.assertEqual(mhandler.get_real_client_addr(), + (x_forwarded_for, x_forwarded_port)) + + mhandler.request.remote_ip = x_real_ip + + mhandler.request.headers.add('X-Real-Ip', x_real_ip) + self.assertEqual(mhandler.get_real_client_addr(), + (x_real_ip, fake_port)) + + mhandler.request.headers.add('X-Real-Port', fake_port + 1) + self.assertEqual(mhandler.get_real_client_addr(), + (x_real_ip, fake_port)) + + mhandler.request.headers['X-Real-Port'] = x_real_port + self.assertEqual(mhandler.get_real_client_addr(), + (x_real_ip, x_real_port)) + + +class TestPrivateKey(unittest.TestCase): + + def get_pk_obj(self, fname, password=None): + key = read_file(make_tests_data_path(fname)) + return PrivateKey(key, password=password, filename=fname) + + def _test_with_encrypted_key(self, fname, password, klass): + pk = self.get_pk_obj(fname, password='') + with self.assertRaises(InvalidValueError) as ctx: + pk.get_pkey_obj() + self.assertIn('Need a passphrase', str(ctx.exception)) + + pk = self.get_pk_obj(fname, password='wrongpass') + with self.assertRaises(InvalidValueError) as ctx: + pk.get_pkey_obj() + self.assertIn('wrong passphrase', str(ctx.exception)) + + pk = self.get_pk_obj(fname, password=password) + self.assertIsInstance(pk.get_pkey_obj(), klass) + + def test_class_with_invalid_key_length(self): + key = u'a' * (PrivateKey.max_length + 1) + + with self.assertRaises(InvalidValueError) as ctx: + PrivateKey(key) + self.assertIn('Invalid key length', str(ctx.exception)) + + def test_get_pkey_obj_with_invalid_key(self): + key = u'a b c' + fname = 'abc' + + pk = PrivateKey(key, filename=fname) + with self.assertRaises(InvalidValueError) as ctx: + pk.get_pkey_obj() + self.assertIn('Invalid key {}'.format(fname), str(ctx.exception)) + + def test_get_pkey_obj_with_plain_rsa_key(self): + pk = self.get_pk_obj('test_rsa.key') + self.assertIsInstance(pk.get_pkey_obj(), paramiko.RSAKey) + + def test_get_pkey_obj_with_plain_ed25519_key(self): + pk = self.get_pk_obj('test_ed25519.key') + self.assertIsInstance(pk.get_pkey_obj(), paramiko.Ed25519Key) + + def test_get_pkey_obj_with_encrypted_rsa_key(self): + fname = 'test_rsa_password.key' + password = 'television' + self._test_with_encrypted_key(fname, password, paramiko.RSAKey) + + def test_get_pkey_obj_with_encrypted_ed25519_key(self): + fname = 'test_ed25519_password.key' + password = 'abc123' + self._test_with_encrypted_key(fname, password, paramiko.Ed25519Key) + + def test_get_pkey_obj_with_encrypted_new_rsa_key(self): + fname = 'test_new_rsa_password.key' + password = '123456' + self._test_with_encrypted_key(fname, password, paramiko.RSAKey) + + def test_get_pkey_obj_with_plain_new_dsa_key(self): + pk = self.get_pk_obj('test_new_dsa.key') + self.assertIsInstance(pk.get_pkey_obj(), paramiko.DSSKey) + + def test_parse_name(self): + key = u'-----BEGIN PRIVATE KEY-----' + pk = PrivateKey(key) + name, _ = pk.parse_name(pk.iostr, pk.tag_to_name) + self.assertIsNone(name) + + key = u'-----BEGIN xxx PRIVATE KEY-----' + pk = PrivateKey(key) + name, _ = pk.parse_name(pk.iostr, pk.tag_to_name) + self.assertIsNone(name) + + key = u'-----BEGIN RSA PRIVATE KEY-----' + pk = PrivateKey(key) + name, _ = pk.parse_name(pk.iostr, pk.tag_to_name) + self.assertIsNone(name) + + key = u'-----BEGIN RSA PRIVATE KEY-----' + pk = PrivateKey(key) + name, _ = pk.parse_name(pk.iostr, pk.tag_to_name) + self.assertIsNone(name) + + key = u'-----BEGIN RSA PRIVATE KEY-----' + pk = PrivateKey(key) + name, _ = pk.parse_name(pk.iostr, pk.tag_to_name) + self.assertIsNone(name) + + for tag, to_name in PrivateKey.tag_to_name.items(): + key = u'-----BEGIN {} PRIVATE KEY----- \r\n'.format(tag) + pk = PrivateKey(key) + name, length = pk.parse_name(pk.iostr, pk.tag_to_name) + self.assertEqual(name, to_name) + self.assertEqual(length, len(key)) + + +class TestWsockHandler(unittest.TestCase): + + def test_check_origin(self): + request = HTTPServerRequest(uri='/') + obj = Mock(spec=WsockHandler, request=request) + + obj.origin_policy = 'same' + request.headers['Host'] = 'www.example.com:4433' + origin = 'https://www.example.com:4433' + self.assertTrue(WsockHandler.check_origin(obj, origin)) + + origin = 'https://www.example.com' + self.assertFalse(WsockHandler.check_origin(obj, origin)) + + obj.origin_policy = 'primary' + self.assertTrue(WsockHandler.check_origin(obj, origin)) + + origin = 'https://blog.example.com' + self.assertTrue(WsockHandler.check_origin(obj, origin)) + + origin = 'https://blog.example.org' + self.assertFalse(WsockHandler.check_origin(obj, origin)) + + origin = 'https://blog.example.org' + obj.origin_policy = {'https://blog.example.org'} + self.assertTrue(WsockHandler.check_origin(obj, origin)) + + origin = 'http://blog.example.org' + obj.origin_policy = {'http://blog.example.org'} + self.assertTrue(WsockHandler.check_origin(obj, origin)) + + origin = 'http://blog.example.org' + obj.origin_policy = {'https://blog.example.org'} + self.assertFalse(WsockHandler.check_origin(obj, origin)) + + obj.origin_policy = '*' + origin = 'https://blog.example.org' + self.assertTrue(WsockHandler.check_origin(obj, origin)) + + def test_failed_weak_ref(self): + request = HTTPServerRequest(uri='/') + obj = Mock(spec=WsockHandler, request=request) + obj.src_addr = ("127.0.0.1", 8888) + + class FakeWeakRef: + def __init__(self): + self.count = 0 + + def __call__(self): + self.count += 1 + return None + + ref = FakeWeakRef() + obj.worker_ref = ref + WsockHandler.on_message(obj, b'{"data": "somestuff"}') + self.assertGreaterEqual(ref.count, 1) + obj.close.assert_called_with(reason='No worker found') + + def test_worker_closed(self): + request = HTTPServerRequest(uri='/') + obj = Mock(spec=WsockHandler, request=request) + obj.src_addr = ("127.0.0.1", 8888) + + class Worker: + def __init__(self): + self.closed = True + + class FakeWeakRef: + def __call__(self): + return Worker() + + ref = FakeWeakRef() + obj.worker_ref = ref + WsockHandler.on_message(obj, b'{"data": "somestuff"}') + obj.close.assert_called_with(reason='Worker closed') diff --git a/resources/images/student-ubuntu/webssh/tests/test_main.py b/resources/images/student-ubuntu/webssh/tests/test_main.py new file mode 100644 index 0000000..6ed89fc --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/test_main.py @@ -0,0 +1,22 @@ +import unittest + +from tornado.web import Application +from webssh import handler +from webssh.main import app_listen + + +class TestMain(unittest.TestCase): + + def test_app_listen(self): + app = Application() + app.listen = lambda x, y, **kwargs: 1 + + handler.redirecting = None + server_settings = dict() + app_listen(app, 80, '127.0.0.1', server_settings) + self.assertFalse(handler.redirecting) + + handler.redirecting = None + server_settings = dict(ssl_options='enabled') + app_listen(app, 80, '127.0.0.1', server_settings) + self.assertTrue(handler.redirecting) diff --git a/resources/images/student-ubuntu/webssh/tests/test_policy.py b/resources/images/student-ubuntu/webssh/tests/test_policy.py new file mode 100644 index 0000000..45b5dd8 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/test_policy.py @@ -0,0 +1,123 @@ +import os +import unittest +import paramiko + +from shutil import copyfile +from paramiko.client import RejectPolicy, WarningPolicy +from tests.utils import make_tests_data_path +from webssh.policy import ( + AutoAddPolicy, get_policy_dictionary, load_host_keys, + get_policy_class, check_policy_setting +) + + +class TestPolicy(unittest.TestCase): + + def test_get_policy_dictionary(self): + classes = [AutoAddPolicy, RejectPolicy, WarningPolicy] + dic = get_policy_dictionary() + for cls in classes: + val = dic[cls.__name__.lower()] + self.assertIs(cls, val) + + def test_load_host_keys(self): + path = '/path-not-exists' + host_keys = load_host_keys(path) + self.assertFalse(host_keys) + + path = '/tmp' + host_keys = load_host_keys(path) + self.assertFalse(host_keys) + + path = make_tests_data_path('known_hosts_example') + host_keys = load_host_keys(path) + self.assertEqual(host_keys, paramiko.hostkeys.HostKeys(path)) + + def test_get_policy_class(self): + keys = ['autoadd', 'reject', 'warning'] + vals = [AutoAddPolicy, RejectPolicy, WarningPolicy] + for key, val in zip(keys, vals): + cls = get_policy_class(key) + self.assertIs(cls, val) + + key = 'non-exists' + with self.assertRaises(ValueError): + get_policy_class(key) + + def test_check_policy_setting(self): + host_keys_filename = make_tests_data_path('host_keys_test.db') + host_keys_settings = dict( + host_keys=paramiko.hostkeys.HostKeys(), + system_host_keys=paramiko.hostkeys.HostKeys(), + host_keys_filename=host_keys_filename + ) + + with self.assertRaises(ValueError): + check_policy_setting(RejectPolicy, host_keys_settings) + + try: + os.unlink(host_keys_filename) + except OSError: + pass + check_policy_setting(AutoAddPolicy, host_keys_settings) + self.assertEqual(os.path.exists(host_keys_filename), True) + + def test_is_missing_host_key(self): + client = paramiko.SSHClient() + file1 = make_tests_data_path('known_hosts_example') + file2 = make_tests_data_path('known_hosts_example2') + client.load_host_keys(file1) + client.load_system_host_keys(file2) + + autoadd = AutoAddPolicy() + for f in [file1, file2]: + entry = paramiko.hostkeys.HostKeys(f)._entries[0] + hostname = entry.hostnames[0] + key = entry.key + self.assertIsNone( + autoadd.is_missing_host_key(client, hostname, key) + ) + + for f in [file1, file2]: + entry = paramiko.hostkeys.HostKeys(f)._entries[0] + hostname = entry.hostnames[0] + key = entry.key + key.get_name = lambda: 'unknown' + self.assertTrue( + autoadd.is_missing_host_key(client, hostname, key) + ) + del key.get_name + + for f in [file1, file2]: + entry = paramiko.hostkeys.HostKeys(f)._entries[0] + hostname = entry.hostnames[0][1:] + key = entry.key + self.assertTrue( + autoadd.is_missing_host_key(client, hostname, key) + ) + + file3 = make_tests_data_path('known_hosts_example3') + entry = paramiko.hostkeys.HostKeys(file3)._entries[0] + hostname = entry.hostnames[0] + key = entry.key + with self.assertRaises(paramiko.BadHostKeyException): + autoadd.is_missing_host_key(client, hostname, key) + + def test_missing_host_key(self): + client = paramiko.SSHClient() + file1 = make_tests_data_path('known_hosts_example') + file2 = make_tests_data_path('known_hosts_example2') + filename = make_tests_data_path('known_hosts') + copyfile(file1, filename) + client.load_host_keys(filename) + n1 = len(client._host_keys) + + autoadd = AutoAddPolicy() + entry = paramiko.hostkeys.HostKeys(file2)._entries[0] + hostname = entry.hostnames[0] + key = entry.key + autoadd.missing_host_key(client, hostname, key) + self.assertEqual(len(client._host_keys), n1 + 1) + self.assertEqual(paramiko.hostkeys.HostKeys(filename), + client._host_keys) + os.unlink(filename) diff --git a/resources/images/student-ubuntu/webssh/tests/test_settings.py b/resources/images/student-ubuntu/webssh/tests/test_settings.py new file mode 100644 index 0000000..bd0d509 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/test_settings.py @@ -0,0 +1,187 @@ +import io +import random +import ssl +import sys +import os.path +import unittest +import paramiko +import tornado.options as options + +from tests.utils import make_tests_data_path +from webssh.policy import load_host_keys +from webssh.settings import ( + get_host_keys_settings, get_policy_setting, base_dir, get_font_filename, + get_ssl_context, get_trusted_downstream, get_origin_setting, print_version, + check_encoding_setting +) +from webssh.utils import UnicodeType +from webssh._version import __version__ + + +class TestSettings(unittest.TestCase): + + def test_print_version(self): + sys_stdout = sys.stdout + sys.stdout = io.StringIO() if UnicodeType == str else io.BytesIO() + + self.assertEqual(print_version(False), None) + self.assertEqual(sys.stdout.getvalue(), '') + + with self.assertRaises(SystemExit): + self.assertEqual(print_version(True), None) + self.assertEqual(sys.stdout.getvalue(), __version__ + '\n') + + sys.stdout = sys_stdout + + def test_get_host_keys_settings(self): + options.hostfile = '' + options.syshostfile = '' + dic = get_host_keys_settings(options) + + filename = os.path.join(base_dir, 'known_hosts') + self.assertEqual(dic['host_keys'], load_host_keys(filename)) + self.assertEqual(dic['host_keys_filename'], filename) + self.assertEqual( + dic['system_host_keys'], + load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) + ) + + options.hostfile = make_tests_data_path('known_hosts_example') + options.syshostfile = make_tests_data_path('known_hosts_example2') + dic2 = get_host_keys_settings(options) + self.assertEqual(dic2['host_keys'], load_host_keys(options.hostfile)) + self.assertEqual(dic2['host_keys_filename'], options.hostfile) + self.assertEqual(dic2['system_host_keys'], + load_host_keys(options.syshostfile)) + + def test_get_policy_setting(self): + options.policy = 'warning' + options.hostfile = '' + options.syshostfile = '' + settings = get_host_keys_settings(options) + instance = get_policy_setting(options, settings) + self.assertIsInstance(instance, paramiko.client.WarningPolicy) + + options.policy = 'autoadd' + options.hostfile = '' + options.syshostfile = '' + settings = get_host_keys_settings(options) + instance = get_policy_setting(options, settings) + self.assertIsInstance(instance, paramiko.client.AutoAddPolicy) + os.unlink(settings['host_keys_filename']) + + options.policy = 'reject' + options.hostfile = '' + options.syshostfile = '' + settings = get_host_keys_settings(options) + try: + instance = get_policy_setting(options, settings) + except ValueError: + self.assertFalse( + settings['host_keys'] and settings['system_host_keys'] + ) + else: + self.assertIsInstance(instance, paramiko.client.RejectPolicy) + + def test_get_ssl_context(self): + options.certfile = '' + options.keyfile = '' + ssl_ctx = get_ssl_context(options) + self.assertIsNone(ssl_ctx) + + options.certfile = 'provided' + options.keyfile = '' + with self.assertRaises(ValueError) as ctx: + ssl_ctx = get_ssl_context(options) + self.assertEqual('keyfile is not provided', str(ctx.exception)) + + options.certfile = '' + options.keyfile = 'provided' + with self.assertRaises(ValueError) as ctx: + ssl_ctx = get_ssl_context(options) + self.assertEqual('certfile is not provided', str(ctx.exception)) + + options.certfile = 'FileDoesNotExist' + options.keyfile = make_tests_data_path('cert.key') + with self.assertRaises(ValueError) as ctx: + ssl_ctx = get_ssl_context(options) + self.assertIn('does not exist', str(ctx.exception)) + + options.certfile = make_tests_data_path('cert.key') + options.keyfile = 'FileDoesNotExist' + with self.assertRaises(ValueError) as ctx: + ssl_ctx = get_ssl_context(options) + self.assertIn('does not exist', str(ctx.exception)) + + options.certfile = make_tests_data_path('cert.key') + options.keyfile = make_tests_data_path('cert.key') + with self.assertRaises(ssl.SSLError) as ctx: + ssl_ctx = get_ssl_context(options) + + options.certfile = make_tests_data_path('cert.crt') + options.keyfile = make_tests_data_path('cert.key') + ssl_ctx = get_ssl_context(options) + self.assertIsNotNone(ssl_ctx) + + def test_get_trusted_downstream(self): + tdstream = '' + result = set() + self.assertEqual(get_trusted_downstream(tdstream), result) + + tdstream = '1.1.1.1, 2.2.2.2' + result = set(['1.1.1.1', '2.2.2.2']) + self.assertEqual(get_trusted_downstream(tdstream), result) + + tdstream = '1.1.1.1, 2.2.2.2, 2.2.2.2' + result = set(['1.1.1.1', '2.2.2.2']) + self.assertEqual(get_trusted_downstream(tdstream), result) + + tdstream = '1.1.1.1, 2.2.2.' + with self.assertRaises(ValueError): + get_trusted_downstream(tdstream) + + def test_get_origin_setting(self): + options.debug = False + options.origin = '*' + with self.assertRaises(ValueError): + get_origin_setting(options) + + options.debug = True + self.assertEqual(get_origin_setting(options), '*') + + options.origin = random.choice(['Same', 'Primary']) + self.assertEqual(get_origin_setting(options), options.origin.lower()) + + options.origin = '' + with self.assertRaises(ValueError): + get_origin_setting(options) + + options.origin = ',' + with self.assertRaises(ValueError): + get_origin_setting(options) + + options.origin = 'www.example.com, https://www.example.org' + result = {'http://www.example.com', 'https://www.example.org'} + self.assertEqual(get_origin_setting(options), result) + + options.origin = 'www.example.com:80, www.example.org:443' + result = {'http://www.example.com', 'https://www.example.org'} + self.assertEqual(get_origin_setting(options), result) + + def test_get_font_setting(self): + font_dir = os.path.join(base_dir, 'tests', 'data', 'fonts') + font = '' + self.assertEqual(get_font_filename(font, font_dir), 'fake-font') + + font = 'fake-font' + self.assertEqual(get_font_filename(font, font_dir), 'fake-font') + + font = 'wrong-name' + with self.assertRaises(ValueError): + get_font_filename(font, font_dir) + + def test_check_encoding_setting(self): + self.assertIsNone(check_encoding_setting('')) + self.assertIsNone(check_encoding_setting('utf-8')) + with self.assertRaises(ValueError): + check_encoding_setting('unknown-encoding') diff --git a/resources/images/student-ubuntu/webssh/tests/test_utils.py b/resources/images/student-ubuntu/webssh/tests/test_utils.py new file mode 100644 index 0000000..5ace48e --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/test_utils.py @@ -0,0 +1,127 @@ +import unittest + +from webssh.utils import ( + is_valid_ip_address, is_valid_port, is_valid_hostname, to_str, to_bytes, + to_int, is_ip_hostname, is_same_primary_domain, parse_origin_from_url +) + + +class TestUitls(unittest.TestCase): + + def test_to_str(self): + b = b'hello' + u = u'hello' + self.assertEqual(to_str(b), u) + self.assertEqual(to_str(u), u) + + def test_to_bytes(self): + b = b'hello' + u = u'hello' + self.assertEqual(to_bytes(b), b) + self.assertEqual(to_bytes(u), b) + + def test_to_int(self): + self.assertEqual(to_int(''), None) + self.assertEqual(to_int(None), None) + self.assertEqual(to_int('22'), 22) + self.assertEqual(to_int(' 22 '), 22) + + def test_is_valid_ip_address(self): + self.assertFalse(is_valid_ip_address('127.0.0')) + self.assertFalse(is_valid_ip_address(b'127.0.0')) + self.assertTrue(is_valid_ip_address('127.0.0.1')) + self.assertTrue(is_valid_ip_address(b'127.0.0.1')) + self.assertFalse(is_valid_ip_address('abc')) + self.assertFalse(is_valid_ip_address(b'abc')) + self.assertTrue(is_valid_ip_address('::1')) + self.assertTrue(is_valid_ip_address(b'::1')) + self.assertTrue(is_valid_ip_address('fe80::1111:2222:3333:4444')) + self.assertTrue(is_valid_ip_address(b'fe80::1111:2222:3333:4444')) + self.assertTrue(is_valid_ip_address('fe80::1111:2222:3333:4444%eth0')) + self.assertTrue(is_valid_ip_address(b'fe80::1111:2222:3333:4444%eth0')) + + def test_is_valid_port(self): + self.assertTrue(is_valid_port(80)) + self.assertFalse(is_valid_port(0)) + self.assertFalse(is_valid_port(65536)) + + def test_is_valid_hostname(self): + self.assertTrue(is_valid_hostname('google.com')) + self.assertTrue(is_valid_hostname('google.com.')) + self.assertTrue(is_valid_hostname('www.google.com')) + self.assertTrue(is_valid_hostname('www.google.com.')) + self.assertFalse(is_valid_hostname('.www.google.com')) + self.assertFalse(is_valid_hostname('http://www.google.com')) + self.assertFalse(is_valid_hostname('https://www.google.com')) + self.assertFalse(is_valid_hostname('127.0.0.1')) + self.assertFalse(is_valid_hostname('::1')) + + def test_is_ip_hostname(self): + self.assertTrue(is_ip_hostname('[::1]')) + self.assertTrue(is_ip_hostname('127.0.0.1')) + self.assertFalse(is_ip_hostname('localhost')) + self.assertFalse(is_ip_hostname('www.google.com')) + + def test_is_same_primary_domain(self): + domain1 = 'localhost' + domain2 = 'localhost' + self.assertTrue(is_same_primary_domain(domain1, domain2)) + + domain1 = 'localhost' + domain2 = 'test' + self.assertFalse(is_same_primary_domain(domain1, domain2)) + + domain1 = 'com' + domain2 = 'example.com' + self.assertFalse(is_same_primary_domain(domain1, domain2)) + + domain1 = 'example.com' + domain2 = 'example.com' + self.assertTrue(is_same_primary_domain(domain1, domain2)) + + domain1 = 'www.example.com' + domain2 = 'example.com' + self.assertTrue(is_same_primary_domain(domain1, domain2)) + + domain1 = 'wwwexample.com' + domain2 = 'example.com' + self.assertFalse(is_same_primary_domain(domain1, domain2)) + + domain1 = 'www.example.com' + domain2 = 'www2.example.com' + self.assertTrue(is_same_primary_domain(domain1, domain2)) + + domain1 = 'xxx.www.example.com' + domain2 = 'xxx.www2.example.com' + self.assertTrue(is_same_primary_domain(domain1, domain2)) + + def test_parse_origin_from_url(self): + url = '' + self.assertIsNone(parse_origin_from_url(url)) + + url = 'www.example.com' + self.assertEqual(parse_origin_from_url(url), 'http://www.example.com') + + url = 'http://www.example.com' + self.assertEqual(parse_origin_from_url(url), 'http://www.example.com') + + url = 'www.example.com:80' + self.assertEqual(parse_origin_from_url(url), 'http://www.example.com') + + url = 'http://www.example.com:80' + self.assertEqual(parse_origin_from_url(url), 'http://www.example.com') + + url = 'www.example.com:443' + self.assertEqual(parse_origin_from_url(url), 'https://www.example.com') + + url = 'https://www.example.com' + self.assertEqual(parse_origin_from_url(url), 'https://www.example.com') + + url = 'https://www.example.com:443' + self.assertEqual(parse_origin_from_url(url), 'https://www.example.com') + + url = 'https://www.example.com:80' + self.assertEqual(parse_origin_from_url(url), url) + + url = 'http://www.example.com:443' + self.assertEqual(parse_origin_from_url(url), url) diff --git a/resources/images/student-ubuntu/webssh/tests/utils.py b/resources/images/student-ubuntu/webssh/tests/utils.py new file mode 100644 index 0000000..4252d0d --- /dev/null +++ b/resources/images/student-ubuntu/webssh/tests/utils.py @@ -0,0 +1,52 @@ +import mimetypes +import os.path +from uuid import uuid4 +from webssh.settings import base_dir + + +def encode_multipart_formdata(fields, files): + """ + fields is a sequence of (name, value) elements for regular form fields. + files is a sequence of (name, filename, value) elements for data to be + uploaded as files. + Return (content_type, body) ready for httplib.HTTP instance + """ + boundary = uuid4().hex + CRLF = '\r\n' + L = [] + for (key, value) in fields: + L.append('--' + boundary) + L.append('Content-Disposition: form-data; name="%s"' % key) + L.append('') + L.append(value) + for (key, filename, value) in files: + L.append('--' + boundary) + L.append( + 'Content-Disposition: form-data; name="%s"; filename="%s"' % ( + key, filename + ) + ) + L.append('Content-Type: %s' % get_content_type(filename)) + L.append('') + L.append(value) + L.append('--' + boundary + '--') + L.append('') + body = CRLF.join(L) + content_type = 'multipart/form-data; boundary=%s' % boundary + return content_type, body + + +def get_content_type(filename): + return mimetypes.guess_type(filename)[0] or 'application/octet-stream' + + +def read_file(path, encoding='utf-8'): + with open(path, 'rb') as f: + data = f.read() + if encoding is None: + return data + return data.decode(encoding) + + +def make_tests_data_path(filename): + return os.path.join(base_dir, 'tests', 'data', filename) diff --git a/resources/images/student-ubuntu/webssh/webssh/__init__.py b/resources/images/student-ubuntu/webssh/webssh/__init__.py new file mode 100644 index 0000000..f165fb4 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/__init__.py @@ -0,0 +1,10 @@ +import sys +from webssh._version import __version__, __version_info__ + + +__author__ = 'Shengdun Hua ' + +if sys.platform == 'win32' and sys.version_info.major == 3 and \ + sys.version_info.minor >= 8: + import asyncio + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) diff --git a/resources/images/student-ubuntu/webssh/webssh/_version.py b/resources/images/student-ubuntu/webssh/webssh/_version.py new file mode 100644 index 0000000..3654932 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/_version.py @@ -0,0 +1,2 @@ +__version_info__ = (1, 6, 1) +__version__ = '.'.join(map(str, __version_info__)) diff --git a/resources/images/student-ubuntu/webssh/webssh/handler.py b/resources/images/student-ubuntu/webssh/webssh/handler.py new file mode 100644 index 0000000..6cfc822 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/handler.py @@ -0,0 +1,603 @@ +import io +import json +import logging +import socket +import struct +import traceback +import weakref +import paramiko +import tornado.web + +from concurrent.futures import ThreadPoolExecutor +from tornado.ioloop import IOLoop +from tornado.options import options +from tornado.process import cpu_count +from webssh.utils import ( + is_valid_ip_address, is_valid_port, is_valid_hostname, to_bytes, to_str, + to_int, to_ip_address, UnicodeType, is_ip_hostname, is_same_primary_domain, + is_valid_encoding +) +from webssh.worker import Worker, recycle_worker, clients + +try: + from json.decoder import JSONDecodeError +except ImportError: + JSONDecodeError = ValueError + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + + +DEFAULT_PORT = 22 + +swallow_http_errors = True +redirecting = None + + +class InvalidValueError(Exception): + pass + + +class SSHClient(paramiko.SSHClient): + + def handler(self, title, instructions, prompt_list): + answers = [] + for prompt_, _ in prompt_list: + prompt = prompt_.strip().lower() + if prompt.startswith('password'): + answers.append(self.password) + elif prompt.startswith('verification'): + answers.append(self.totp) + else: + raise ValueError('Unknown prompt: {}'.format(prompt_)) + return answers + + def auth_interactive(self, username, handler): + if not self.totp: + raise ValueError('Need a verification code for 2fa.') + self._transport.auth_interactive(username, handler) + + def _auth(self, username, password, pkey, *args): + self.password = password + saved_exception = None + two_factor = False + allowed_types = set() + two_factor_types = {'keyboard-interactive', 'password'} + + if pkey is not None: + logging.info('Trying publickey authentication') + try: + allowed_types = set( + self._transport.auth_publickey(username, pkey) + ) + two_factor = allowed_types & two_factor_types + if not two_factor: + return + except paramiko.SSHException as e: + saved_exception = e + + if two_factor: + logging.info('Trying publickey 2fa') + return self.auth_interactive(username, self.handler) + + if password is not None: + logging.info('Trying password authentication') + try: + self._transport.auth_password(username, password) + return + except paramiko.SSHException as e: + saved_exception = e + allowed_types = set(getattr(e, 'allowed_types', [])) + two_factor = allowed_types & two_factor_types + + if two_factor: + logging.info('Trying password 2fa') + return self.auth_interactive(username, self.handler) + + assert saved_exception is not None + raise saved_exception + + +class PrivateKey(object): + + max_length = 16384 # rough number + + tag_to_name = { + 'RSA': 'RSA', + 'DSA': 'DSS', + 'EC': 'ECDSA', + 'OPENSSH': 'Ed25519' + } + + def __init__(self, privatekey, password=None, filename=''): + self.privatekey = privatekey + self.filename = filename + self.password = password + self.check_length() + self.iostr = io.StringIO(privatekey) + self.last_exception = None + + def check_length(self): + if len(self.privatekey) > self.max_length: + raise InvalidValueError('Invalid key length.') + + def parse_name(self, iostr, tag_to_name): + name = None + for line_ in iostr: + line = line_.strip() + if line and line.startswith('-----BEGIN ') and \ + line.endswith(' PRIVATE KEY-----'): + lst = line.split(' ') + if len(lst) == 4: + tag = lst[1] + if tag: + name = tag_to_name.get(tag) + if name: + break + return name, len(line_) + + def get_specific_pkey(self, name, offset, password): + self.iostr.seek(offset) + logging.debug('Reset offset to {}.'.format(offset)) + + logging.debug('Try parsing it as {} type key'.format(name)) + pkeycls = getattr(paramiko, name+'Key') + pkey = None + + try: + pkey = pkeycls.from_private_key(self.iostr, password=password) + except paramiko.PasswordRequiredException: + raise InvalidValueError('Need a passphrase to decrypt the key.') + except (paramiko.SSHException, ValueError) as exc: + self.last_exception = exc + logging.debug(str(exc)) + + return pkey + + def get_pkey_obj(self): + logging.info('Parsing private key {!r}'.format(self.filename)) + name, length = self.parse_name(self.iostr, self.tag_to_name) + if not name: + raise InvalidValueError('Invalid key {}.'.format(self.filename)) + + offset = self.iostr.tell() - length + password = to_bytes(self.password) if self.password else None + pkey = self.get_specific_pkey(name, offset, password) + + if pkey is None and name == 'Ed25519': + for name in ['RSA', 'ECDSA', 'DSS']: + pkey = self.get_specific_pkey(name, offset, password) + if pkey: + break + + if pkey: + return pkey + + logging.error(str(self.last_exception)) + msg = 'Invalid key' + if self.password: + msg += ' or wrong passphrase "{}" for decrypting it.'.format( + self.password) + raise InvalidValueError(msg) + + +class MixinHandler(object): + + custom_headers = { + 'Server': 'TornadoServer' + } + + html = ('{code} {reason}{code} ' + '{reason}') + + def initialize(self, loop=None): + self.check_request() + self.loop = loop + self.origin_policy = self.settings.get('origin_policy') + + def check_request(self): + context = self.request.connection.context + result = self.is_forbidden(context, self.request.host_name) + self._transforms = [] + if result: + self.set_status(403) + self.finish( + self.html.format(code=self._status_code, reason=self._reason) + ) + elif result is False: + to_url = self.get_redirect_url( + self.request.host_name, options.sslport, self.request.uri + ) + self.redirect(to_url, permanent=True) + else: + self.context = context + + def check_origin(self, origin): + if self.origin_policy == '*': + return True + + parsed_origin = urlparse(origin) + netloc = parsed_origin.netloc.lower() + logging.debug('netloc: {}'.format(netloc)) + + host = self.request.headers.get('Host') + logging.debug('host: {}'.format(host)) + + if netloc == host: + return True + + if self.origin_policy == 'same': + return False + elif self.origin_policy == 'primary': + return is_same_primary_domain(netloc.rsplit(':', 1)[0], + host.rsplit(':', 1)[0]) + else: + return origin in self.origin_policy + + def is_forbidden(self, context, hostname): + ip = context.address[0] + lst = context.trusted_downstream + ip_address = None + + if lst and ip not in lst: + logging.warning( + 'IP {!r} not found in trusted downstream {!r}'.format(ip, lst) + ) + return True + + if context._orig_protocol == 'http': + if redirecting and not is_ip_hostname(hostname): + ip_address = to_ip_address(ip) + if not ip_address.is_private: + # redirecting + return False + + if options.fbidhttp: + if ip_address is None: + ip_address = to_ip_address(ip) + if not ip_address.is_private: + logging.warning('Public plain http request is forbidden.') + return True + + def get_redirect_url(self, hostname, port, uri): + port = '' if port == 443 else ':%s' % port + return 'https://{}{}{}'.format(hostname, port, uri) + + def set_default_headers(self): + for header in self.custom_headers.items(): + self.set_header(*header) + + def get_value(self, name): + value = self.get_argument(name) + if not value: + raise InvalidValueError('Missing value {}'.format(name)) + return value + + def get_context_addr(self): + return self.context.address[:2] + + def get_client_addr(self): + if options.xheaders: + return self.get_real_client_addr() or self.get_context_addr() + else: + return self.get_context_addr() + + def get_real_client_addr(self): + ip = self.request.remote_ip + + if ip == self.request.headers.get('X-Real-Ip'): + port = self.request.headers.get('X-Real-Port') + elif ip in self.request.headers.get('X-Forwarded-For', ''): + port = self.request.headers.get('X-Forwarded-Port') + else: + # not running behind an nginx server + return + + port = to_int(port) + if port is None or not is_valid_port(port): + # fake port + port = 65535 + + return (ip, port) + + +class NotFoundHandler(MixinHandler, tornado.web.ErrorHandler): + + def initialize(self): + super(NotFoundHandler, self).initialize() + + def prepare(self): + raise tornado.web.HTTPError(404) + + +class IndexHandler(MixinHandler, tornado.web.RequestHandler): + + executor = ThreadPoolExecutor(max_workers=cpu_count()*5) + + def initialize(self, loop, policy, host_keys_settings): + super(IndexHandler, self).initialize(loop) + self.policy = policy + self.host_keys_settings = host_keys_settings + self.ssh_client = self.get_ssh_client() + self.debug = self.settings.get('debug', False) + self.font = self.settings.get('font', '') + self.result = dict(id=None, status=None, encoding=None) + + def write_error(self, status_code, **kwargs): + if swallow_http_errors and self.request.method == 'POST': + exc_info = kwargs.get('exc_info') + if exc_info: + reason = getattr(exc_info[1], 'log_message', None) + if reason: + self._reason = reason + self.result.update(status=self._reason) + self.set_status(200) + self.finish(self.result) + else: + super(IndexHandler, self).write_error(status_code, **kwargs) + + def get_ssh_client(self): + ssh = SSHClient() + ssh._system_host_keys = self.host_keys_settings['system_host_keys'] + ssh._host_keys = self.host_keys_settings['host_keys'] + ssh._host_keys_filename = self.host_keys_settings['host_keys_filename'] + ssh.set_missing_host_key_policy(self.policy) + return ssh + + def get_privatekey(self): + name = 'privatekey' + lst = self.request.files.get(name) + if lst: + # multipart form + filename = lst[0]['filename'] + data = lst[0]['body'] + value = self.decode_argument(data, name=name).strip() + else: + # urlencoded form + value = self.get_argument(name, u'') + filename = '' + + return value, filename + + def get_hostname(self): + value = self.get_value('hostname') + if not (is_valid_hostname(value) or is_valid_ip_address(value)): + raise InvalidValueError('Invalid hostname: {}'.format(value)) + return value + + def get_port(self): + value = self.get_argument('port', u'') + if not value: + return DEFAULT_PORT + + port = to_int(value) + if port is None or not is_valid_port(port): + raise InvalidValueError('Invalid port: {}'.format(value)) + return port + + def lookup_hostname(self, hostname, port): + key = hostname if port == 22 else '[{}]:{}'.format(hostname, port) + + if self.ssh_client._system_host_keys.lookup(key) is None: + if self.ssh_client._host_keys.lookup(key) is None: + raise tornado.web.HTTPError( + 403, 'Connection to {}:{} is not allowed.'.format( + hostname, port) + ) + + def get_args(self): + hostname = self.get_hostname() + port = self.get_port() + username = self.get_value('username') + password = self.get_argument('password', u'') + privatekey, filename = self.get_privatekey() + passphrase = self.get_argument('passphrase', u'') + totp = self.get_argument('totp', u'') + + if isinstance(self.policy, paramiko.RejectPolicy): + self.lookup_hostname(hostname, port) + + if privatekey: + pkey = PrivateKey(privatekey, passphrase, filename).get_pkey_obj() + else: + pkey = None + + self.ssh_client.totp = totp + args = (hostname, port, username, password, pkey) + logging.debug(args) + + return args + + def parse_encoding(self, data): + try: + encoding = to_str(data.strip(), 'ascii') + except UnicodeDecodeError: + return + + if is_valid_encoding(encoding): + return encoding + + def get_default_encoding(self, ssh): + commands = [ + '$SHELL -ilc "locale charmap"', + '$SHELL -ic "locale charmap"' + ] + + for command in commands: + try: + _, stdout, _ = ssh.exec_command(command, + get_pty=True, + timeout=1) + except paramiko.SSHException as exc: + logging.info(str(exc)) + else: + try: + data = stdout.read() + except socket.timeout: + pass + else: + logging.debug('{!r} => {!r}'.format(command, data)) + result = self.parse_encoding(data) + if result: + return result + + logging.warning('Could not detect the default encoding.') + return 'utf-8' + + def ssh_connect(self, args): + ssh = self.ssh_client + dst_addr = args[:2] + logging.info('Connecting to {}:{}'.format(*dst_addr)) + + try: + ssh.connect(*args, timeout=options.timeout) + except socket.error: + raise ValueError('Unable to connect to {}:{}'.format(*dst_addr)) + except paramiko.BadAuthenticationType: + raise ValueError('Bad authentication type.') + except paramiko.AuthenticationException: + raise ValueError('Authentication failed.') + except paramiko.BadHostKeyException: + raise ValueError('Bad host key.') + + term = self.get_argument('term', u'') or u'xterm' + chan = ssh.invoke_shell(term=term) + chan.setblocking(0) + worker = Worker(self.loop, ssh, chan, dst_addr) + worker.encoding = options.encoding if options.encoding else \ + self.get_default_encoding(ssh) + return worker + + def check_origin(self): + event_origin = self.get_argument('_origin', u'') + header_origin = self.request.headers.get('Origin') + origin = event_origin or header_origin + + if origin: + if not super(IndexHandler, self).check_origin(origin): + raise tornado.web.HTTPError( + 403, 'Cross origin operation is not allowed.' + ) + + if not event_origin and self.origin_policy != 'same': + self.set_header('Access-Control-Allow-Origin', origin) + + def head(self): + pass + + def get(self): + self.render('index.html', debug=self.debug, font=self.font) + + @tornado.gen.coroutine + def post(self): + if self.debug and self.get_argument('error', u''): + # for testing purpose only + raise ValueError('Uncaught exception') + + ip, port = self.get_client_addr() + workers = clients.get(ip, {}) + if workers and len(workers) >= options.maxconn: + raise tornado.web.HTTPError(403, 'Too many live connections.') + + self.check_origin() + + try: + args = self.get_args() + except InvalidValueError as exc: + raise tornado.web.HTTPError(400, str(exc)) + + future = self.executor.submit(self.ssh_connect, args) + + try: + worker = yield future + except (ValueError, paramiko.SSHException) as exc: + logging.error(traceback.format_exc()) + self.result.update(status=str(exc)) + else: + if not workers: + clients[ip] = workers + worker.src_addr = (ip, port) + workers[worker.id] = worker + self.loop.call_later(options.delay, recycle_worker, worker) + self.result.update(id=worker.id, encoding=worker.encoding) + + self.write(self.result) + + +class WsockHandler(MixinHandler, tornado.websocket.WebSocketHandler): + + def initialize(self, loop): + super(WsockHandler, self).initialize(loop) + self.worker_ref = None + + def open(self): + self.src_addr = self.get_client_addr() + logging.info('Connected from {}:{}'.format(*self.src_addr)) + + workers = clients.get(self.src_addr[0]) + if not workers: + self.close(reason='Websocket authentication failed.') + return + + try: + worker_id = self.get_value('id') + except (tornado.web.MissingArgumentError, InvalidValueError) as exc: + self.close(reason=str(exc)) + else: + worker = workers.get(worker_id) + if worker: + workers[worker_id] = None + self.set_nodelay(True) + worker.set_handler(self) + self.worker_ref = weakref.ref(worker) + self.loop.add_handler(worker.fd, worker, IOLoop.READ) + else: + self.close(reason='Websocket authentication failed.') + + def on_message(self, message): + logging.debug('{!r} from {}:{}'.format(message, *self.src_addr)) + worker = self.worker_ref() + if not worker: + # The worker has likely been closed. Do not process. + logging.debug( + "received message to closed worker from {}:{}".format( + *self.src_addr + ) + ) + self.close(reason='No worker found') + return + + if worker.closed: + self.close(reason='Worker closed') + return + + try: + msg = json.loads(message) + except JSONDecodeError: + return + + if not isinstance(msg, dict): + return + + resize = msg.get('resize') + if resize and len(resize) == 2: + try: + worker.chan.resize_pty(*resize) + except (TypeError, struct.error, paramiko.SSHException): + pass + + data = msg.get('data') + if data and isinstance(data, UnicodeType): + worker.data_to_dst.append(data) + worker.on_write() + + def on_close(self): + logging.info('Disconnected from {}:{}'.format(*self.src_addr)) + if not self.close_reason: + self.close_reason = 'client disconnected' + + worker = self.worker_ref() if self.worker_ref else None + if worker: + worker.close(reason=self.close_reason) diff --git a/resources/images/student-ubuntu/webssh/webssh/main.py b/resources/images/student-ubuntu/webssh/webssh/main.py new file mode 100644 index 0000000..5faad10 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/main.py @@ -0,0 +1,58 @@ +import logging +import tornado.web +import tornado.ioloop + +from tornado.options import options +from webssh import handler +from webssh.handler import IndexHandler, WsockHandler, NotFoundHandler +from webssh.settings import ( + get_app_settings, get_host_keys_settings, get_policy_setting, + get_ssl_context, get_server_settings, check_encoding_setting +) + + +def make_handlers(loop, options): + host_keys_settings = get_host_keys_settings(options) + policy = get_policy_setting(options, host_keys_settings) + + handlers = [ + (r'/', IndexHandler, dict(loop=loop, policy=policy, + host_keys_settings=host_keys_settings)), + (r'/ws', WsockHandler, dict(loop=loop)) + ] + return handlers + + +def make_app(handlers, settings): + settings.update(default_handler_class=NotFoundHandler) + return tornado.web.Application(handlers, **settings) + + +def app_listen(app, port, address, server_settings): + app.listen(port, address, **server_settings) + if not server_settings.get('ssl_options'): + server_type = 'http' + else: + server_type = 'https' + handler.redirecting = True if options.redirect else False + logging.info( + 'Listening on {}:{} ({})'.format(address, port, server_type) + ) + + +def main(): + options.parse_command_line() + check_encoding_setting(options.encoding) + loop = tornado.ioloop.IOLoop.current() + app = make_app(make_handlers(loop, options), get_app_settings(options)) + ssl_ctx = get_ssl_context(options) + server_settings = get_server_settings(options) + app_listen(app, options.port, options.address, server_settings) + if ssl_ctx: + server_settings.update(ssl_options=ssl_ctx) + app_listen(app, options.sslport, options.ssladdress, server_settings) + loop.start() + + +if __name__ == '__main__': + main() diff --git a/resources/images/student-ubuntu/webssh/webssh/policy.py b/resources/images/student-ubuntu/webssh/webssh/policy.py new file mode 100644 index 0000000..30d818f --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/policy.py @@ -0,0 +1,86 @@ +import logging +import os.path +import threading +import paramiko + + +def load_host_keys(path): + if os.path.exists(path) and os.path.isfile(path): + return paramiko.hostkeys.HostKeys(filename=path) + return paramiko.hostkeys.HostKeys() + + +def get_policy_dictionary(): + dic = { + k.lower(): v for k, v in vars(paramiko.client).items() if type(v) + is type and issubclass(v, paramiko.client.MissingHostKeyPolicy) + and v is not paramiko.client.MissingHostKeyPolicy + } + return dic + + +def get_policy_class(policy): + origin_policy = policy + policy = policy.lower() + if not policy.endswith('policy'): + policy += 'policy' + + dic = get_policy_dictionary() + logging.debug(dic) + + try: + cls = dic[policy] + except KeyError: + raise ValueError('Unknown policy {!r}'.format(origin_policy)) + return cls + + +def check_policy_setting(policy_class, host_keys_settings): + host_keys = host_keys_settings['host_keys'] + host_keys_filename = host_keys_settings['host_keys_filename'] + system_host_keys = host_keys_settings['system_host_keys'] + + if policy_class is paramiko.client.AutoAddPolicy: + host_keys.save(host_keys_filename) # for permission test + elif policy_class is paramiko.client.RejectPolicy: + if not host_keys and not system_host_keys: + raise ValueError( + 'Reject policy could not be used without host keys.' + ) + + +class AutoAddPolicy(paramiko.client.MissingHostKeyPolicy): + """ + thread-safe AutoAddPolicy + """ + lock = threading.Lock() + + def is_missing_host_key(self, client, hostname, key): + k = client._system_host_keys.lookup(hostname) or \ + client._host_keys.lookup(hostname) + if k is None: + return True + host_key = k.get(key.get_name(), None) + if host_key is None: + return True + if host_key != key: + raise paramiko.BadHostKeyException(hostname, key, host_key) + + def missing_host_key(self, client, hostname, key): + with self.lock: + if self.is_missing_host_key(client, hostname, key): + keytype = key.get_name() + logging.info( + 'Adding {} host key for {}'.format(keytype, hostname) + ) + client._host_keys._entries.append( + paramiko.hostkeys.HostKeyEntry([hostname], key) + ) + + with open(client._host_keys_filename, 'a') as f: + f.write('{} {} {}\n'.format( + hostname, keytype, key.get_base64() + )) + + +paramiko.client.AutoAddPolicy = AutoAddPolicy diff --git a/resources/images/student-ubuntu/webssh/webssh/settings.py b/resources/images/student-ubuntu/webssh/webssh/settings.py new file mode 100644 index 0000000..b02b79e --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/settings.py @@ -0,0 +1,198 @@ +import logging +import os.path +import ssl +import sys + +from tornado.options import define +from webssh.policy import ( + load_host_keys, get_policy_class, check_policy_setting +) +from webssh.utils import ( + to_ip_address, parse_origin_from_url, is_valid_encoding +) +from webssh._version import __version__ + + +def print_version(flag): + if flag: + print(__version__) + sys.exit(0) + + +define('address', default='', help='Listen address') +define('port', type=int, default=8888, help='Listen port') +define('ssladdress', default='', help='SSL listen address') +define('sslport', type=int, default=4433, help='SSL listen port') +define('certfile', default='', help='SSL certificate file') +define('keyfile', default='', help='SSL private key file') +define('debug', type=bool, default=False, help='Debug mode') +define('policy', default='warning', + help='Missing host key policy, reject|autoadd|warning') +define('hostfile', default='', help='User defined host keys file') +define('syshostfile', default='', help='System wide host keys file') +define('tdstream', default='', help='Trusted downstream, separated by comma') +define('redirect', type=bool, default=True, help='Redirecting http to https') +define('fbidhttp', type=bool, default=True, + help='Forbid public plain http incoming requests') +define('xheaders', type=bool, default=True, help='Support xheaders') +define('xsrf', type=bool, default=True, help='CSRF protection') +define('origin', default='same', help='''Origin policy, +'same': same origin policy, matches host name and port number; +'primary': primary domain policy, matches primary domain only; +'': custom domains policy, matches any domain in the list +separated by comma; +'*': wildcard policy, matches any domain, allowed in debug mode only.''') +define('wpintvl', type=float, default=0, help='Websocket ping interval') +define('timeout', type=float, default=3, help='SSH connection timeout') +define('delay', type=float, default=3, help='The delay to call recycle_worker') +define('maxconn', type=int, default=20, + help='Maximum live connections (ssh sessions) per client') +define('font', default='', help='custom font filename') +define('encoding', default='', + help='''The default character encoding of ssh servers. +Example: --encoding='utf-8' to solve the problem with some switches&routers''') +define('version', type=bool, help='Show version information', + callback=print_version) + + +base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +font_dirs = ['webssh', 'static', 'css', 'fonts'] +max_body_size = 1 * 1024 * 1024 + + +class Font(object): + + def __init__(self, filename, dirs): + self.family = self.get_family(filename) + self.url = self.get_url(filename, dirs) + + def get_family(self, filename): + return filename.split('.')[0] + + def get_url(self, filename, dirs): + return '/'.join(dirs + [filename]) + + +def get_app_settings(options): + settings = dict( + template_path=os.path.join(base_dir, 'webssh', 'templates'), + static_path=os.path.join(base_dir, 'webssh', 'static'), + websocket_ping_interval=options.wpintvl, + debug=options.debug, + xsrf_cookies=options.xsrf, + font=Font( + get_font_filename(options.font, + os.path.join(base_dir, *font_dirs)), + font_dirs[1:] + ), + origin_policy=get_origin_setting(options) + ) + return settings + + +def get_server_settings(options): + settings = dict( + xheaders=options.xheaders, + max_body_size=max_body_size, + trusted_downstream=get_trusted_downstream(options.tdstream) + ) + return settings + + +def get_host_keys_settings(options): + if not options.hostfile: + host_keys_filename = os.path.join(base_dir, 'known_hosts') + else: + host_keys_filename = options.hostfile + host_keys = load_host_keys(host_keys_filename) + + if not options.syshostfile: + filename = os.path.expanduser('~/.ssh/known_hosts') + else: + filename = options.syshostfile + system_host_keys = load_host_keys(filename) + + settings = dict( + host_keys=host_keys, + system_host_keys=system_host_keys, + host_keys_filename=host_keys_filename + ) + return settings + + +def get_policy_setting(options, host_keys_settings): + policy_class = get_policy_class(options.policy) + logging.info(policy_class.__name__) + check_policy_setting(policy_class, host_keys_settings) + return policy_class() + + +def get_ssl_context(options): + if not options.certfile and not options.keyfile: + return None + elif not options.certfile: + raise ValueError('certfile is not provided') + elif not options.keyfile: + raise ValueError('keyfile is not provided') + elif not os.path.isfile(options.certfile): + raise ValueError('File {!r} does not exist'.format(options.certfile)) + elif not os.path.isfile(options.keyfile): + raise ValueError('File {!r} does not exist'.format(options.keyfile)) + else: + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain(options.certfile, options.keyfile) + return ssl_ctx + + +def get_trusted_downstream(tdstream): + result = set() + for ip in tdstream.split(','): + ip = ip.strip() + if ip: + to_ip_address(ip) + result.add(ip) + return result + + +def get_origin_setting(options): + if options.origin == '*': + if not options.debug: + raise ValueError( + 'Wildcard origin policy is only allowed in debug mode.' + ) + else: + return '*' + + origin = options.origin.lower() + if origin in ['same', 'primary']: + return origin + + origins = set() + for url in origin.split(','): + orig = parse_origin_from_url(url) + if orig: + origins.add(orig) + + if not origins: + raise ValueError('Empty origin list') + + return origins + + +def get_font_filename(font, font_dir): + filenames = {f for f in os.listdir(font_dir) if not f.startswith('.') + and os.path.isfile(os.path.join(font_dir, f))} + if font: + if font not in filenames: + raise ValueError( + 'Font file {!r} not found'.format(os.path.join(font_dir, font)) + ) + elif filenames: + font = filenames.pop() + + return font + + +def check_encoding_setting(encoding): + if encoding and not is_valid_encoding(encoding): + raise ValueError('Unknown character encoding {!r}.'.format(encoding)) diff --git a/resources/images/student-ubuntu/webssh/webssh/static/css/bootstrap.min.css b/resources/images/student-ubuntu/webssh/webssh/static/css/bootstrap.min.css new file mode 100644 index 0000000..b950ada --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/static/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.3.0 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#28a745}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#dc3545}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:calc(1rem + .4rem);padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion>.card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion>.card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.accordion>.card .card-header{margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#545b62}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-sm .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-md .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-lg .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-xl .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush .list-group-item:last-child{margin-bottom:-1px}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{margin-bottom:0;border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #dee2e6;border-bottom-right-radius:.3rem;border-bottom-left-radius:.3rem}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:0s .6s opacity}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:spinner-border .75s linear infinite;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:spinner-grow .75s linear infinite;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;overflow-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/resources/images/student-ubuntu/webssh/webssh/static/css/fullscreen.min.css b/resources/images/student-ubuntu/webssh/webssh/static/css/fullscreen.min.css new file mode 100644 index 0000000..0d97f10 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/static/css/fullscreen.min.css @@ -0,0 +1,2 @@ +.xterm.fullscreen{position:fixed;top:0;bottom:0;left:0;right:0;width:auto;height:auto;z-index:255} +/*# sourceMappingURL=fullscreen.min.css.map */ \ No newline at end of file diff --git a/resources/images/student-ubuntu/webssh/webssh/static/css/xterm.min.css b/resources/images/student-ubuntu/webssh/webssh/static/css/xterm.min.css new file mode 100644 index 0000000..792731e --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/static/css/xterm.min.css @@ -0,0 +1 @@ +.xterm{font-feature-settings:"liga" 0;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#FFF;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm{cursor:text}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility,.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:0.5}.xterm-underline{text-decoration:underline} \ No newline at end of file diff --git a/resources/images/student-ubuntu/webssh/webssh/static/img/favicon.png b/resources/images/student-ubuntu/webssh/webssh/static/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..0b281be918e2eb553ac6fdb60a9eb1c4ada80d84 GIT binary patch literal 5953 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 literal 0 HcmV?d00001 diff --git a/resources/images/student-ubuntu/webssh/webssh/static/js/bootstrap.min.js b/resources/images/student-ubuntu/webssh/webssh/static/js/bootstrap.min.js new file mode 100644 index 0000000..33bf17b --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/static/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.3.0 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("jquery"),require("popper.js")):"function"==typeof define&&define.amd?define(["exports","jquery","popper.js"],e):e((t=t||self).bootstrap={},t.jQuery,t.Popper)}(this,function(t,g,u){"use strict";function i(t,e){for(var n=0;nthis._items.length-1||t<0))if(this._isSliding)g(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right

    ',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},Ae="show",Ne="out",Oe={HIDE:"hide"+Ce,HIDDEN:"hidden"+Ce,SHOW:"show"+Ce,SHOWN:"shown"+Ce,INSERTED:"inserted"+Ce,CLICK:"click"+Ce,FOCUSIN:"focusin"+Ce,FOCUSOUT:"focusout"+Ce,MOUSEENTER:"mouseenter"+Ce,MOUSELEAVE:"mouseleave"+Ce},ke="fade",Pe="show",Le=".tooltip-inner",je=".arrow",He="hover",Re="focus",Ue="click",We="manual",xe=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Pe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(ke);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:je},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Pe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===Ne&&e._leave(null,e)};if(g(this.tip).hasClass(ke)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==Ae&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Pe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ue]=!1,this._activeTrigger[Re]=!1,this._activeTrigger[He]=!1,g(this.tip).hasClass(ke)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Se+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Le)),this.getTitle()),g(t).removeClass(ke+" "+Pe)},t.setElementContent=function(t,e){var n=this.config.html;"object"==typeof e&&(e.nodeType||e.jquery)?n?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text()):t[n?"html":"text"](e)},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return De[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==We){var e=t===He?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===He?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Re:He]=!0),g(e.getTipElement()).hasClass(Pe)||e._hoverState===Ae?e._hoverState=Ae:(clearTimeout(e._timeout),e._hoverState=Ae,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===Ae&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Re:He]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=Ne,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===Ne&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){return"number"==typeof(t=l({},this.constructor.Default,g(this.element).data(),"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(ye,t,this.constructor.DefaultType),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(be);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(ke),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ee),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ee,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.0"}},{key:"Default",get:function(){return we}},{key:"NAME",get:function(){return ye}},{key:"DATA_KEY",get:function(){return Ee}},{key:"Event",get:function(){return Oe}},{key:"EVENT_KEY",get:function(){return Ce}},{key:"DefaultType",get:function(){return Ie}}]),i}();g.fn[ye]=xe._jQueryInterface,g.fn[ye].Constructor=xe,g.fn[ye].noConflict=function(){return g.fn[ye]=Te,xe._jQueryInterface};var Fe="popover",qe="bs.popover",Me="."+qe,Ke=g.fn[Fe],Qe="bs-popover",Be=new RegExp("(^|\\s)"+Qe+"\\S+","g"),Ve=l({},xe.Default,{placement:"right",trigger:"click",content:"",template:''}),Ye=l({},xe.DefaultType,{content:"(string|element|function)"}),Xe="fade",ze="show",Ge=".popover-header",Je=".popover-body",Ze={HIDE:"hide"+Me,HIDDEN:"hidden"+Me,SHOW:"show"+Me,SHOWN:"shown"+Me,INSERTED:"inserted"+Me,CLICK:"click"+Me,FOCUSIN:"focusin"+Me,FOCUSOUT:"focusout"+Me,MOUSEENTER:"mouseenter"+Me,MOUSELEAVE:"mouseleave"+Me},$e=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Qe+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(Ge),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(Je),e),t.removeClass(Xe+" "+ze)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Be);null!==e&&0=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + + + + + + diff --git a/resources/images/student-ubuntu/webssh/webssh/utils.py b/resources/images/student-ubuntu/webssh/webssh/utils.py new file mode 100644 index 0000000..845ca56 --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/utils.py @@ -0,0 +1,145 @@ +import ipaddress +import re + +try: + from types import UnicodeType +except ImportError: + UnicodeType = str + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + + +numeric = re.compile(r'[0-9]+$') +allowed = re.compile(r'(?!-)[a-z0-9-]{1,63}(? 253: + return False + + labels = hostname.split('.') + + # the TLD must be not all-numeric + if numeric.match(labels[-1]): + return False + + return all(allowed.match(label) for label in labels) + + +def is_same_primary_domain(domain1, domain2): + i = -1 + dots = 0 + l1 = len(domain1) + l2 = len(domain2) + m = min(l1, l2) + + while i >= -m: + c1 = domain1[i] + c2 = domain2[i] + + if c1 == c2: + if c1 == '.': + dots += 1 + if dots == 2: + return True + else: + return False + + i -= 1 + + if l1 == l2: + return True + + if dots == 0: + return False + + c = domain1[i] if l1 > m else domain2[i] + return c == '.' + + +def parse_origin_from_url(url): + url = url.strip() + if not url: + return + + if not (url.startswith('http://') or url.startswith('https://') or + url.startswith('//')): + url = '//' + url + + parsed = urlparse(url) + port = parsed.port + scheme = parsed.scheme + + if scheme == '': + scheme = 'https' if port == 443 else 'http' + + if port == 443 and scheme == 'https': + netloc = parsed.netloc.replace(':443', '') + elif port == 80 and scheme == 'http': + netloc = parsed.netloc.replace(':80', '') + else: + netloc = parsed.netloc + + return '{}://{}'.format(scheme, netloc) diff --git a/resources/images/student-ubuntu/webssh/webssh/worker.py b/resources/images/student-ubuntu/webssh/webssh/worker.py new file mode 100644 index 0000000..130e53a --- /dev/null +++ b/resources/images/student-ubuntu/webssh/webssh/worker.py @@ -0,0 +1,134 @@ +import logging +try: + import secrets +except ImportError: + secrets = None +import tornado.websocket + +from uuid import uuid4 +from tornado.ioloop import IOLoop +from tornado.iostream import _ERRNO_CONNRESET +from tornado.util import errno_from_exception + + +BUF_SIZE = 32 * 1024 +clients = {} # {ip: {id: worker}} + + +def clear_worker(worker, clients): + ip = worker.src_addr[0] + workers = clients.get(ip) + assert worker.id in workers + workers.pop(worker.id) + + if not workers: + clients.pop(ip) + if not clients: + clients.clear() + + +def recycle_worker(worker): + if worker.handler: + return + logging.warning('Recycling worker {}'.format(worker.id)) + worker.close(reason='worker recycled') + + +class Worker(object): + def __init__(self, loop, ssh, chan, dst_addr): + self.loop = loop + self.ssh = ssh + self.chan = chan + self.dst_addr = dst_addr + self.fd = chan.fileno() + self.id = self.gen_id() + self.data_to_dst = [] + self.handler = None + self.mode = IOLoop.READ + self.closed = False + + def __call__(self, fd, events): + if events & IOLoop.READ: + self.on_read() + if events & IOLoop.WRITE: + self.on_write() + if events & IOLoop.ERROR: + self.close(reason='error event occurred') + + @classmethod + def gen_id(cls): + return secrets.token_urlsafe(nbytes=32) if secrets else uuid4().hex + + def set_handler(self, handler): + if not self.handler: + self.handler = handler + + def update_handler(self, mode): + if self.mode != mode: + self.loop.update_handler(self.fd, mode) + self.mode = mode + if mode == IOLoop.WRITE: + self.loop.call_later(0.1, self, self.fd, IOLoop.WRITE) + + def on_read(self): + logging.debug('worker {} on read'.format(self.id)) + try: + data = self.chan.recv(BUF_SIZE) + except (OSError, IOError) as e: + logging.error(e) + if self.chan.closed or errno_from_exception(e) in _ERRNO_CONNRESET: + self.close(reason='chan error on reading') + else: + logging.debug('{!r} from {}:{}'.format(data, *self.dst_addr)) + if not data: + self.close(reason='chan closed') + return + + logging.debug('{!r} to {}:{}'.format(data, *self.handler.src_addr)) + try: + self.handler.write_message(data, binary=True) + except tornado.websocket.WebSocketClosedError: + self.close(reason='websocket closed') + + def on_write(self): + logging.debug('worker {} on write'.format(self.id)) + if not self.data_to_dst: + return + + data = ''.join(self.data_to_dst) + logging.debug('{!r} to {}:{}'.format(data, *self.dst_addr)) + + try: + sent = self.chan.send(data) + except (OSError, IOError) as e: + logging.error(e) + if self.chan.closed or errno_from_exception(e) in _ERRNO_CONNRESET: + self.close(reason='chan error on writing') + else: + self.update_handler(IOLoop.WRITE) + else: + self.data_to_dst = [] + data = data[sent:] + if data: + self.data_to_dst.append(data) + self.update_handler(IOLoop.WRITE) + else: + self.update_handler(IOLoop.READ) + + def close(self, reason=None): + if self.closed: + return + self.closed = True + + logging.info( + 'Closing worker {} with reason: {}'.format(self.id, reason) + ) + if self.handler: + self.loop.remove_handler(self.fd) + self.handler.close(reason=reason) + self.chan.close() + self.ssh.close() + logging.info('Connection to {}:{} lost'.format(*self.dst_addr)) + + clear_worker(self, clients) + logging.debug(clients)