diff --git a/.all-contributorsrc b/.all-contributorsrc index 78c931202..d175b8231 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -531,6 +531,123 @@ "contributions": [ "code" ] + }, + { + "login": "JDPowell648", + "name": "JDPowell648", + "avatar_url": "https://avatars.githubusercontent.com/u/41934552?v=4", + "profile": "https://github.com/JDPowell648", + "contributions": [ + "doc" + ] + }, + { + "login": "Adriankhl", + "name": "k.h.lai", + "avatar_url": "https://avatars.githubusercontent.com/u/16377650?v=4", + "profile": "https://github.com/Adriankhl", + "contributions": [ + "code" + ] + }, + { + "login": "gruebel", + "name": "Anton Grübel", + "avatar_url": "https://avatars.githubusercontent.com/u/33207684?v=4", + "profile": "https://github.com/gruebel", + "contributions": [ + "code" + ] + }, + { + "login": "flange-ipb", + "name": "flange-ipb", + "avatar_url": "https://avatars.githubusercontent.com/u/34936695?v=4", + "profile": "https://github.com/flange-ipb", + "contributions": [ + "code" + ] + }, + { + "login": "pmp-p", + "name": "Paul m. p. Peny", + "avatar_url": "https://avatars.githubusercontent.com/u/16009100?v=4", + "profile": "https://discuss.afpy.org/", + "contributions": [ + "code" + ] + }, + { + "login": "DavidRConnell", + "name": "David R. Connell", + "avatar_url": "https://avatars.githubusercontent.com/u/35470740?v=4", + "profile": "https://davidrconnell.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "rmmaf", + "name": "Rodrigo Monteiro de Moraes de Arruda Falcão", + "avatar_url": "https://avatars.githubusercontent.com/u/23747884?v=4", + "profile": "https://www.linkedin.com/in/rmmaf/", + "contributions": [ + "code" + ] + }, + { + "login": "Kreijstal", + "name": "Kreijstal", + "avatar_url": "https://avatars.githubusercontent.com/u/2415206?v=4", + "profile": "https://github.com/Kreijstal", + "contributions": [ + "code" + ] + }, + { + "login": "m1-s", + "name": "Michael Schneider", + "avatar_url": "https://avatars.githubusercontent.com/u/94642227?v=4", + "profile": "https://github.com/m1-s", + "contributions": [ + "code" + ] + }, + { + "login": "aothms", + "name": "Thomas Krijnen", + "avatar_url": "https://avatars.githubusercontent.com/u/1096535?v=4", + "profile": "http://thomaskrijnen.com/", + "contributions": [ + "code" + ] + }, + { + "login": "GenieTim", + "name": "Tim Bernhard", + "avatar_url": "https://avatars.githubusercontent.com/u/8596965?v=4", + "profile": "https://github.com/GenieTim", + "contributions": [ + "code" + ] + }, + { + "login": "BeaMarton13", + "name": "Bea Márton", + "avatar_url": "https://avatars.githubusercontent.com/u/204701577?v=4", + "profile": "https://github.com/BeaMarton13", + "contributions": [ + "code" + ] + }, + { + "login": "SKG24", + "name": "Sanat Kumar Gupta", + "avatar_url": "https://avatars.githubusercontent.com/u/123228827?v=4", + "profile": "https://github.com/SKG24", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7 diff --git a/.dockerignore b/.dockerignore index 4bd21acf4..f14524756 100644 --- a/.dockerignore +++ b/.dockerignore @@ -12,4 +12,3 @@ dist/* # also ignore build folder for vendored stuff vendor/build/* vendor/install/* - diff --git a/.git_archival.json b/.git_archival.json new file mode 100644 index 000000000..9869b5923 --- /dev/null +++ b/.git_archival.json @@ -0,0 +1,7 @@ +{ + "hash-full": "$Format:%H$", + "hash-short": "$Format:%h$", + "timestamp": "$Format:%cI$", + "refs": "$Format:%D$", + "describe": "$Format:%(describe:tags=true,match=[0-9]*)$" +} diff --git a/.gitattributes b/.gitattributes index c7158f857..56669188e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -*.c linguist-language=Python +.git_archival.json export-subst diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..71e72eb9a --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: igraph +open_collective: igraph diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 31afa92c3..60eeaa013 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -19,4 +19,3 @@ Explain when and for what purpose the feature would be useful. **References** List any relevant references (papers or books describing relevant algorithms). - diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..686944ff0 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ + + + + +- [ ] By submitting this pull request, I assign the copyright of my contribution to _The igraph development team_. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 491497be4..2192d7c72 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,84 +1,85 @@ -name: Build and test, upload to PyPI on release +# Name cannot contain commas because of setup-emsdk job +name: Build and test on: [push, pull_request] env: + CIBW_ENABLE: pypy CIBW_ENVIRONMENT_PASS_LINUX: PYTEST_TIMEOUT + CIBW_PROJECT_REQUIRES_PYTHON: ">=3.9" CIBW_TEST_COMMAND: "cd {project} && pip install --prefer-binary '.[test]' && python -m pytest -v tests" - CIBW_SKIP: "cp36-*" + # Free-threaded builds excluded for Python 3.14 because they do not support the limited API + CIBW_SKIP: "cp314t-*" PYTEST_TIMEOUT: 60 - MACOSX_DEPLOYMENT_TARGET: "10.9" jobs: build_wheel_linux: - name: Build wheels on Linux (${{ matrix.wheel_arch }}) - runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - wheel_arch: [x86_64, i686] - + name: Build wheels on Linux (x86_64) + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true fetch-depth: 0 - - uses: actions/setup-python@v4 - name: Install Python - with: - python-version: '3.8' - - name: Build wheels (manylinux) - uses: pypa/cibuildwheel@v2.11.1 + uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BEFORE_BUILD: "yum install -y flex bison libxml2-devel zlib-devel && pip install -U cmake pip wheel && python setup.py build_c_core" - CIBW_BUILD: "*-manylinux_${{ matrix.wheel_arch }}" - # Skip tests for Python 3.10 and 3.11 because SciPy does not have - # 32-bit wheels for Linux - CIBW_TEST_SKIP: "cp310-manylinux_i686 cp311-manylinux_i686" + CIBW_BEFORE_BUILD: "yum install -y flex bison libxml2-devel zlib-devel cairo-devel && pip install -U cmake pip setuptools wheel && python setup.py build_c_core" + CIBW_BUILD: "*-manylinux_x86_64" - name: Build wheels (musllinux) - uses: pypa/cibuildwheel@v2.11.1 + uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BEFORE_BUILD: "apk add flex bison libxml2-dev zlib-dev && pip install -U cmake pip wheel && python setup.py build_c_core" - CIBW_BUILD: "*-musllinux_${{ matrix.wheel_arch }}" + CIBW_BEFORE_BUILD: "apk add flex bison libxml2-dev zlib-dev cairo-dev && pip install -U cmake pip setuptools wheel && python setup.py build_c_core" + CIBW_BUILD: "*-musllinux_x86_64" CIBW_TEST_COMMAND: "cd {project} && pip install --prefer-binary '.[test-musl]' && python -m pytest -v tests" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v6 with: + name: wheels-linux-x86_64 path: ./wheelhouse/*.whl - build_wheel_linux_aarch64: - name: Build wheels on Linux (aarch64) - runs-on: ubuntu-20.04 - if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + build_wheel_linux_aarch64_manylinux: + name: Build wheels on Linux (aarch64/manylinux) + runs-on: ubuntu-22.04-arm steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true fetch-depth: 0 - - name: Set up QEMU - id: qemu - uses: docker/setup-qemu-action@v2 - - name: Build wheels (manylinux) - uses: pypa/cibuildwheel@v2.11.1 + uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BEFORE_BUILD: "yum install -y flex bison libxml2-devel zlib-devel && pip install -U cmake pip wheel && python setup.py build_c_core" + CIBW_BEFORE_BUILD: "yum install -y flex bison libxml2-devel zlib-devel cairo-devel && pip install -U cmake pip setuptools wheel && python setup.py build_c_core" CIBW_ARCHS_LINUX: aarch64 CIBW_BUILD: "*-manylinux_aarch64" + - uses: actions/upload-artifact@v6 + with: + name: wheels-linux-aarch64-manylinux + path: ./wheelhouse/*.whl + + build_wheel_linux_aarch64_musllinux: + name: Build wheels on Linux (aarch64/musllinux) + runs-on: ubuntu-22.04-arm + steps: + - uses: actions/checkout@v5 + with: + submodules: true + fetch-depth: 0 + - name: Build wheels (musllinux) - uses: pypa/cibuildwheel@v2.11.1 + uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BEFORE_BUILD: "apk add flex bison libxml2-dev zlib-dev && pip install -U cmake pip wheel && python setup.py build_c_core" + CIBW_BEFORE_BUILD: "apk add flex bison libxml2-dev zlib-dev cairo-dev && pip install -U cmake pip setuptools wheel && python setup.py build_c_core" CIBW_ARCHS_LINUX: aarch64 CIBW_BUILD: "*-musllinux_aarch64" CIBW_TEST_COMMAND: "cd {project} && pip install --prefer-binary '.[test-musl]' && python -m pytest -v tests" - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v6 with: + name: wheels-linux-aarch64-musllinux path: ./wheelhouse/*.whl build_wheel_macos: @@ -86,6 +87,7 @@ jobs: runs-on: macos-latest env: LLVM_VERSION: "14.0.5" + MACOSX_DEPLOYMENT_TARGET: "10.15" strategy: matrix: include: @@ -96,34 +98,28 @@ jobs: wheel_arch: arm64 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true fetch-depth: 0 - name: Cache installed C core id: cache-c-core - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: vendor/install key: C-core-cache-${{ runner.os }}-${{ matrix.cmake_arch }}-llvm${{ env.LLVM_VERSION }}-${{ hashFiles('.git/modules/**/HEAD') }} - name: Cache C core dependencies id: cache-c-deps - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: ~/local key: deps-cache-v2-${{ runner.os }}-${{ matrix.cmake_arch }}-llvm${{ env.LLVM_VERSION }} - - uses: actions/setup-python@v4 - name: Install Python - with: - python-version: '3.8' - - name: Install OS dependencies if: steps.cache-c-core.outputs.cache-hit != 'true' || steps.cache-c-deps.outputs.cache-hit != 'true' # Only needed when building the C core or libomp - run: - brew install ninja autoconf automake libtool cmake + run: brew install autoconf automake libtool - name: Install OpenMP library if: steps.cache-c-deps.outputs.cache-hit != 'true' @@ -137,50 +133,96 @@ jobs: cmake --install . - name: Build wheels - uses: pypa/cibuildwheel@v2.11.1 + uses: pypa/cibuildwheel@v3.3.0 env: CIBW_ARCHS_MACOS: "${{ matrix.wheel_arch }}" - CIBW_BEFORE_BUILD: "python setup.py build_c_core" + CIBW_BEFORE_BUILD: "pip install -U setuptools && python setup.py build_c_core" CIBW_ENVIRONMENT: "LDFLAGS=-L$HOME/local/lib" IGRAPH_CMAKE_EXTRA_ARGS: -DCMAKE_OSX_ARCHITECTURES=${{ matrix.cmake_arch }} ${{ matrix.cmake_extra_args }} -DCMAKE_PREFIX_PATH=$HOME/local - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v6 with: + name: wheels-macos-${{ matrix.wheel_arch }} path: ./wheelhouse/*.whl + build_wheel_wasm: + name: Build wheels for WebAssembly + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v5 + with: + submodules: true + fetch-depth: 0 + + - uses: actions/setup-python@v6 + name: Install Python + with: + python-version: "3.12.1" + + - name: Install OS dependencies + run: sudo apt install ninja-build cmake flex bison + + - uses: mymindstorm/setup-emsdk@v14 + with: + version: "3.1.58" + actions-cache-folder: "emsdk-cache" + + - name: Build wheel + run: | + pip install pyodide-build==0.26.2 + python3 scripts/fix_pyodide_build.py + pyodide build + + - name: Setup upterm session + uses: lhotari/action-upterm@v1 + if: ${{ failure() }} + with: + limit-access-to-actor: true + wait-timeout-minutes: 5 + + - uses: actions/upload-artifact@v6 + with: + name: wheels-wasm + path: ./dist/*.whl + build_wheel_win: name: Build wheels on Windows (${{ matrix.cmake_arch }}) - runs-on: windows-2019 strategy: matrix: include: - cmake_arch: Win32 wheel_arch: win32 vcpkg_arch: x86 + os: windows-2022 + test_extra: test - cmake_arch: x64 wheel_arch: win_amd64 vcpkg_arch: x64 + os: windows-2022 + test_extra: test + - cmake_arch: ARM64 + wheel_arch: win_arm64 + vcpkg_arch: arm64 + os: windows-11-arm + test_extra: test-win-arm64 + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true fetch-depth: 0 - - uses: actions/setup-python@v4 - name: Install Python - with: - python-version: '3.8' - - name: Cache installed C core id: cache-c-core - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: vendor/install key: C-core-cache-${{ runner.os }}-${{ matrix.cmake_arch }}-${{ hashFiles('.git/modules/**/HEAD') }} - name: Cache VCPKG - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: C:/vcpkg/installed/ key: vcpkg-${{ runner.os }}-${{ matrix.vcpkg_arch }} @@ -192,40 +234,41 @@ jobs: - name: Install VCPKG libraries run: | %VCPKG_INSTALLATION_ROOT%\vcpkg.exe integrate install - %VCPKG_INSTALLATION_ROOT%\vcpkg.exe install libxml2:${{ matrix.vcpkg_arch }}-windows-static-md + %VCPKG_INSTALLATION_ROOT%\vcpkg.exe install liblzma:${{ matrix.vcpkg_arch }}-windows-static-md libxml2:${{ matrix.vcpkg_arch }}-windows-static-md shell: cmd - name: Build wheels - uses: pypa/cibuildwheel@v2.11.1 + uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BEFORE_BUILD: "python setup.py build_c_core" + CIBW_BEFORE_BUILD: "pip install -U setuptools && python setup.py build_c_core" CIBW_BUILD: "*-${{ matrix.wheel_arch }}" - CIBW_TEST_COMMAND: "cd /d {project} && pip install --prefer-binary \".[test]\" && python -m pytest tests" - # Skip tests for Python 3.10 and 3.11 because SciPy does not have - # 32-bit wheels for Windows - CIBW_TEST_SKIP: "cp310-win32 cp311-win32" + CIBW_TEST_COMMAND: 'cd /d {project} && pip install --prefer-binary ".[${{ matrix.test_extra }}]" && python -m pytest tests' + # Skip tests for Python 3.10 onwards because SciPy does not have + # 32-bit wheels for Windows any more + CIBW_TEST_SKIP: "cp310-win32 cp311-win32 cp312-win32 cp313-win32 cp314-win32" IGRAPH_CMAKE_EXTRA_ARGS: -DCMAKE_BUILD_TYPE=RelWithDebInfo -DVCPKG_TARGET_TRIPLET=${{ matrix.vcpkg_arch }}-windows-static-md -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake -A ${{ matrix.cmake_arch }} IGRAPH_EXTRA_LIBRARY_PATH: C:/vcpkg/installed/${{ matrix.vcpkg_arch }}-windows-static-md/lib/ IGRAPH_STATIC_EXTENSION: True - IGRAPH_EXTRA_LIBRARIES: libxml2,lzma,zlib,iconv,charset + IGRAPH_EXTRA_LIBRARIES: libxml2,lzma,zlib,iconv,charset,bcrypt IGRAPH_EXTRA_DYNAMIC_LIBRARIES: wsock32,ws2_32 - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v6 with: + name: wheels-win-${{ matrix.wheel_arch }} path: ./wheelhouse/*.whl build_sdist: name: Build sdist and test extra dependencies runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true fetch-depth: 0 - name: Cache installed C core id: cache-c-core - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: | vendor/install @@ -233,88 +276,77 @@ jobs: - name: Install OS dependencies if: steps.cache-c-core.outputs.cache-hit != 'true' # Only needed when building the C core - run: - sudo apt install ninja-build cmake flex bison + run: sudo apt install ninja-build cmake flex bison - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v6 name: Install Python with: - python-version: '3.8' + python-version: "3.9" - name: Build sdist run: | python setup.py build_c_core python setup.py sdist - python setup.py install + pip install . - name: Test run: | - pip install --prefer-binary numpy scipy pandas networkx pytest pytest-timeout + pip install '.[test]' python -m pytest -v tests - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v6 with: + name: sdist path: dist/*.tar.gz # When updating 'runs-on', the ASan/UBSan library paths/versions must also be updated for LD_PRELOAD # for the "Test" step below. - # - # The C core is temporarily compiled with -DCMAKE_C_FLAGS="-DNDEBUG" because the Python test suite - # triggers a bug/assertion in RNG_INTEGER(): https://github.com/igraph/igraph/issues/2031 - # When this bug is fixed, remove NDEBUG and increment the cache version to v1. build_with_sanitizer: name: Build with sanitizers for debugging purposes - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest env: - CC: "gcc -fsanitize=address -fsanitize=undefined" - CXX: "g++ -fsanitize=address -fsanitize=undefined" - CFLAGS: "-g -Og -fno-omit-frame-pointer -fdiagnostics-color" - CXXFLAGS: "-g -Og -fno-omit-frame-pointer -fdiagnostics-color" - IGRAPH_CMAKE_EXTRA_ARGS: -DUSE_SANITIZER="Address;Undefined" -DCMAKE_BUILD_TYPE=Debug -DFLEX_KEEP_LINE_NUMBERS=ON -DFORCE_COLORED_OUTPUT=ON -DCMAKE_C_FLAGS="-DNDEBUG" + IGRAPH_CMAKE_EXTRA_ARGS: -DFORCE_COLORED_OUTPUT=ON steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 with: submodules: true fetch-depth: 0 - + - name: Cache installed C core id: cache-c-core - uses: actions/cache@v3 + uses: actions/cache@v5 with: path: | vendor/build vendor/install - key: C-core-build-sanitizer-v0-${{ runner.os }}-${{ hashFiles('.git/modules/vendor/source/igraph/HEAD') }} + key: C-core-build-sanitizer-v1-${{ runner.os }}-${{ hashFiles('.git/modules/vendor/source/igraph/HEAD') }} - name: Install OS dependencies if: steps.cache-c-core.outputs.cache-hit != 'true' # Only needed when building the C core - run: - sudo apt install ninja-build cmake flex bison + run: sudo apt install ninja-build cmake flex bison - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v6 name: Install Python with: - python-version: '3.11.0-rc.2' - - - name: Build C core - run: | - python setup.py build_c_core + python-version: "3.12" - name: Build and install Python extension + env: + IGRAPH_USE_SANITIZERS: 1 run: | - # NOTE: install calls "build" first - python setup.py install - - - name: Install test dependencies - run: | - pip install --prefer-binary pytest pytest-timeout + # We cannot install the test dependency group because many test dependencies cause + # false positives in the sanitizer + pip install --prefer-binary networkx pytest pytest-timeout + pip install -e . # Only pytest, and nothing else should be run in this section due to the presence of LD_PRELOAD. # The ASan/UBSan library versions need to be updated when switching to a newer Ubuntu/GCC. - # Leak detection is disabled because of many false (?) positives in Python itself. + # LD_PRELOAD needs to be specified in the "run" section to ensure that we + # do not pick up memory leaks in the wrapper shell (e.g., /bin/bash) - name: Test env: - LD_PRELOAD: "/lib/x86_64-linux-gnu/libasan.so.5:/lib/x86_64-linux-gnu/libubsan.so.1" - ASAN_OPTIONS: "detect_leaks=0" + ASAN_OPTIONS: "detect_stack_use_after_return=1" + LSAN_OPTIONS: "suppressions=etc/lsan-suppr.txt:print_suppressions=false" run: | - python -m pytest --capture=sys tests + sudo sysctl vm.mmap_rnd_bits=28 + LD_PRELOAD=/lib/x86_64-linux-gnu/libasan.so.8:/lib/x86_64-linux-gnu/libubsan.so.1 python -m pytest --capture=sys tests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..e67e6d125 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,15 @@ +fail_fast: true +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: end-of-file-fixer + exclude: ^tests/drawing/plotly/baseline_images + - id: trailing-whitespace + + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.3.5 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7af56aadb..7de01065a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -21,7 +21,7 @@ build: - zlib1g-dev tools: - python: "3.9" + python: "3.11" # You can also specify other tool versions: # nodejs: "16" # rust: "1.55" @@ -46,4 +46,3 @@ sphinx: python: install: - requirements: doc/source/requirements.txt - diff --git a/CHANGELOG.md b/CHANGELOG.md index a8cbd22f5..f2424f4fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,353 @@ # igraph Python interface changelog +## 1.0.1 - 2025-12-26 + +### Changed + +- The C core of igraph was updated to version 1.0.1. + +## [1.0.0] - 2025-10-23 + +### Added + +- Added `Graph.Nearest_Neighbor_Graph()`. + +- Added `node_in_weights` argument to `Graph.community_leiden()`. + +- Added `align_layout()` to align the principal axes of a layout nicely + with screen dimensions. + +- Added `Graph.commnity_voronoi()`. + +- Added `Graph.commnity_fluid_communities()`. + +### Changed + +- The C core of igraph was updated to version 1.0.0. + +- Most layouts are now auto-aligned using `align_layout()`. + +- Dropped support for PyPy 3.9 and PyPy 3.10 as they are now EOL. + +### Miscellaneous + +- Documentation improvements. + +- This is the last version that supports Python 3.9 as it will reach its + end of life at the end of October 2025. + +## [0.11.9] - 2025-06-11 + +### Changed + +- Dropped support for Python 3.8 as it has now reached its end of life. + +- The C core of igraph was updated to version 0.10.16. + +- Added `Graph.simple_cycles()` to find simple cycles in the graph. + +## [0.11.8] - 2024-10-25 + +### Fixed + +- Fixed documentation build on Read The Docs. No other changes compared to + 0.11.7. + +## [0.11.7] - 2024-10-24 + +### Added + +- Added `Graph.feedback_vertex_set()` to calculate a feedback vertex set of the + graph. + +- Added new methods to `Graph.feedback_arc_set()` that allows the user to + select the specific integer problem formulation used by the underlying + solver. + +### Changed + +- Ensured compatibility with Python 3.13. + +- The C core of igraph was updated to an interim commit (3dd336a) between + version 0.10.13 and version 0.10.15. Earlier versions of this changelog + mistakenly marked this revision as version 0.10.14. + +### Fixed + +- Fixed a potential memory leak in the `Graph.get_shortest_path_astar()` heuristic + function callback + +## [0.11.6] - 2024-07-08 + +### Added + +- Added `Graph.Hypercube()` for creating n-dimensional hypercube graphs. + +- Added `Graph.Chung_Lu()` for sampling from the Chung-Lu model as well as + several related models. + +- Added `Graph.is_complete()` to test if there is a connection between all + distinct pairs of vertices. + +- Added `Graph.is_clique()` to test if a set of vertices forms a clique. + +- Added `Graph.is_independent_vertex_set()` to test if some vertices form an + independent set. + +- Added `Graph.mean_degree()` for a convenient way to compute the average + degree of a graph. + +### Changed + +- The C core of igraph was updated to version 0.10.13. + +- `Graph.rewire()` now attempts to perform edge swaps 10 times the number of + edges by default. + +- Error messages issued when an attribute is not found now mention the name + and type of that attribute. + +## [0.11.5] - 2024-05-07 + +### Added + +- Added a `prefixattr=...` keyword argument to `Graph.write_graphml()` that + allows the user to strip the `g_`, `v_` and `e_` prefixes from GraphML files + written by igraph. + +### Changed + +- `Graph.are_connected()` has now been renamed to `Graph.are_adjacent()`, + following up a similar change in the C core. The old name of the function + is deprecated but will be kept around until at least 0.12.0. + +- The C core of igraph was updated to version 0.10.12. + +- Deprecated `PyCObject` API calls in the C code were replaced by calls to + `PyCapsule`, thanks to @DavidRConnell in + + +- `get_shortest_path()` documentation was clarified by @JDPowell648 in + + +- It is now possible to link to an existing igraph C core on MSYS2, thanks to + @Kreijstal in + +### Fixed + +- Bugfix in the NetworkX graph conversion code by @rmmaf in + + +## [0.11.4] + +### Added + +- Added `Graph.Prufer()` to construct a graph from a Prüfer sequence. + +- Added `Graph.Bipartite_Degree_Sequence()` to construct a bipartite graph from + a bidegree sequence. + +- Added `Graph.is_biconnected()` to check if a graph is biconnected. + +### Fixed + +- Fixed import of `graph-tool` graphs for vertex properties where each property + has a vector value. + +- `Graph.Adjacency()` now accepts `Matrix` instances and other sequences as an + input, it is not limited to lists-of-lists-of-ints any more. + +## [0.11.3] - 2023-11-19 + +### Added + +- Added `Graph.__invalidate_cache()` for debugging and benchmarking purposes. + +### Changed + +- The C core of igraph was updated to version 0.10.8. + +### Fixed + +- Removed incorrectly added `loops=...` argument of `Graph.is_bigraphical()`. + +- Fixed a bug in the Matplotlib graph drawing backend that filled the interior of undirected curved edges. + +## [0.11.2] - 2023-10-12 + +### Fixed + +- Fixed plotting of null graphs with the Matplotlib backend. + +## [0.11.0] - 2023-10-12 + +### Added + +- `python-igraph` is now tested in Python 3.12. + +- Added `weights=...` keyword argument to `Graph.layout_kamada_kawai()`. + +### Changed + +- The `matplotlib` plotting infrastructure underwent major surgery and is now able to show consistent vertex and edge drawings at any level of zoom, including with animations, and for any aspect ratio. +- As a consequence of the restructuring at the previous point, vertex sizes are now specified in figure points and are not affected by axis limits or zoom. With the current conventions, `vertex_size=25` is a reasonable size for `igraph.plot`. +- As another consequence of the above, vertex labels now support offsets from the vertex center, in figure point units. +- As another consequence of the above, self loops are now looking better and their size can be controlled using the `edge_loop_size` argument in `igraph.plot`. +- As another consequence of the above, if using the `matplotlib` backend when plotting a graph, `igraph.plot` now does not return the `Axes` anymore. Instead, it returns a container artist called `GraphArtist`, which contains as children the elements of the graph plot: a `VertexCollection` for the vertices, and `EdgeCollection` for the edges, and so on. These objects can be used to modify the plot after the initial rendering, e.g. inside a Jupyter notebook, to fine tune the appearance of the plot. While documentation on specific graphic elements is still scant, more descriptive examples will follow in the future. + +### Fixed + +- Fixed drawing order of vertices in the Plotly backend (#691). + +### Removed + +- Dropped support for Python 3.7 as it has reached its end of life. + +## [0.10.8] - 2023-09-12 + +### Added + +- Added `is_bigraphical()` to test whether a pair of integer sequences can be the degree sequence of some bipartite graph. + +- Added `weights=...` keyword argument to `Graph.radius()` and `Graph.eccentricity()`. + +## [0.10.7] - 2023-09-04 + +### Added + +- `Graph.distances()`, `Graph.get_shortest_path()` and `Graph.get_shortest_paths()` now allow the user to select the algorithm to be used explicitly. + +### Changed + +- The C core of igraph was updated to version 0.10.7. + +- `Graph.distances()` now uses Dijkstra's algorithm when there are zero weights but no negative weights. Earlier versions switched to Bellman-Ford or Johnson in the presence of zero weights unnecessarily. + +### Fixed + +- Fixed a bug in `EdgeSeq.select(_incident=...)` for undirected graphs. + +- Fixed a memory leak in `Graph.distances()` when attempting to use Johnson's algorithm with `mode != "out"` + +## [0.10.6] - 2023-07-13 + +### Changed + +- The C core of igraph was updated to version 0.10.6. + +- `Graph.Incidence()` is now deprecated in favour of `Graph.Biadjacency()` as it constructs a bipartite graph from a _bipartite adjacency_ matrix. (The previous name was a mistake). Future versions might re-introduce `Graph.Incidence()` to construct a graph from its incidence matrix. + +- `Graph.get_incidence()` is now deprecated in favour of `Graph.get_biadjacency()` as it returns the _bipartite adjacency_ matrix of a graph and not its incidence matrix. (The previous name was a mistake). Future versions might re-introduce `Graph.get_incidence()` to return the incidence matrix of a graph. + +- Reverted the change in 0.10.5 that prevented adding vertices with integers as vertex names. Now we show a deprecation warning instead, and the addition of vertices with integer names will be prevented from version 0.11.0 only. + +### Fixed + +- Fixed a minor memory leak in `Graph.decompose()`. + +- The default vertex size of the Plotly backend was fixed so the vertices are + now visible by default without specifying an explicit size for them. + +## [0.10.5] - 2023-06-30 + +### Added + +- The `plot()` function now takes a `backend` keyword argument that can be used + to specify the plotting backend explicitly. + +- The `VertexClustering` object returned from `Graph.community_leiden()` now + contains an extra property named `quality` that stores the value of the + internal quality function optimized by the algorithm. + +- `Graph.Adjacency()` and `Graph.Weighted_Adjacency()` now supports + `loops="once"`, `loops="twice"` and `loops="ignore"` to control how loop + edges are handled in a more granular way. `loops=True` and `loops=False` + keep on working as in earlier versions. + +- Added `Graph.get_shortest_path()` as a convenience function for cases when + only one shortest path is needed between a given source and target vertices. + +- Added `Graph.get_shortest_path_astar()` to calculate the shortest path + between two vertices using the A-star algorithm and an appropriate + heuristic function. + +- Added `Graph.count_automorphisms()` to count the number of automorphisms + of a graph and `Graph.automorphism_group()` to calculate the generators of + the automorphism group of a graph. + +- The `VertexCover` constructor now allows referring to vertices by names + instead of IDs. + +### Fixed + +- `resolution` parameter is now correctly taken into account when calling + `Graph.modularity()` + +- `VertexClustering.giant()` now accepts the null graph. The giant component of + a null graph is the null graph according to our conventions. + +- `Graph.layout_reingold_tilford()` now accepts vertex names in the `roots=...` + keyword argument. + +- The plotting of curved directed edges with the Cairo backend is now fixed; + arrowheads were placed at the wrong position before this fix. + +### Changed + +- The C core of igraph was updated to version 0.10.5. + +### Removed + +- Removed defunct `Graph.community_leading_eigenvector_naive()` method. Not a + breaking change because it was already removed from the C core a long time + ago so the function in the Python interface did not do anything useful + either. + +## [0.10.4] - 2023-01-27 + +### Added + +- Added `Graph.vertex_coloring_greedy()` to calculate a greedy vertex coloring + for the graph. + +- Betweenness and edge betweenness scores can now be calculated for a subset of + the shortest paths originating from or terminating in a certain set of + vertices only. + +### Fixed + +- Fixed the drawing of `VertexDendrogram` instances, both in the Cairo and the + Matplotlib backends. +- The `cutoff` and `normalized` arguments of `Graph.closeness()` did not function correctly. + +## [0.10.3] - 2022-12-31 + +### Changed + +- The C core of igraph was updated to version 0.10.3. + +- UMAP layout now exposes the computation of the symmetrized edge weights via + `umap_compute_weights()`. The layout function, `Graph.layout_umap()`, can + now be called either on a directed graph with edge distances, or on an + undirected graph with edge weights, typically computed via + `umap_compute_weights()` or precomputed by the user. Moreover, the + `sampling_prob` argument was faulty and has been removed. See PR + [#613](https://github.com/igraph/python-igraph/pull/613) for details. + +- The `resolution_parameter` argument of `Graph.community_leiden()` was renamed + to `resolution` for sake of consistency. The old variant still works with a + deprecation warning, but will be removed in a future version. + +### Fixed + +- `Graph.Data_Frame()` now handles the `Int64` data type from `pandas`, thanks + to [@Adriankhl](https://github.com/Adriankhl). See PR + [#609](https://github.com/igraph/python-igraph/pull/609) for details. + +- `Graph.layout_lgl()` `root` argument is now optional (as it should have been). + +- The `VertexClustering` class now handles partial dendrograms correctly. + ## [0.10.2] - 2022-10-14 ### Added @@ -64,7 +412,7 @@ plotting backends, controlled by a configuration option. See PR [#425](https://github.com/igraph/python-igraph/pull/425) for more details. -- Added support for additional ways to construct a graph, such as from a +- Added support for additional ways to construct a graph, such as from a dictionary of dictionaries, and to export a graph object back to those data structures. See PR [#434](https://github.com/igraph/python-igraph/pull/434) for more details. @@ -170,7 +518,7 @@ [#503](https://github.com/igraph/python-igraph/issues/503) for details. - Fixed potential memory leaks in `Graph.maximum_cardinality_search()`, - `Graph.get_all_simple_paths()`, `Graph.get_subisomorphisms_lad()`, + `Graph.get_all_simple_paths()`, `Graph.get_subisomorphisms_lad()`, `Graph.community_edge_betweenness()`, as well as the `union` and `intersection` operators. @@ -409,11 +757,26 @@ ## [0.8.3] This is the last released version of `python-igraph` without a changelog file. -Please refer to the commit logs at https://github.com/igraph/python-igraph for +Please refer to the commit logs at for a list of changes affecting versions up to 0.8.3. Notable changes after 0.8.3 are documented above. -[Unreleased]: https://github.com/igraph/python-igraph/compare/0.10.2...master +[1.0.0]: https://github.com/igraph/python-igraph/compare/0.11.9...1.0.0 +[0.11.9]: https://github.com/igraph/python-igraph/compare/0.11.8...0.11.9 +[0.11.8]: https://github.com/igraph/python-igraph/compare/0.11.7...0.11.8 +[0.11.7]: https://github.com/igraph/python-igraph/compare/0.11.6...0.11.7 +[0.11.6]: https://github.com/igraph/python-igraph/compare/0.11.5...0.11.6 +[0.11.5]: https://github.com/igraph/python-igraph/compare/0.11.4...0.11.5 +[0.11.4]: https://github.com/igraph/python-igraph/compare/0.11.3...0.11.4 +[0.11.3]: https://github.com/igraph/python-igraph/compare/0.11.2...0.11.3 +[0.11.2]: https://github.com/igraph/python-igraph/compare/0.11.0...0.11.2 +[0.11.0]: https://github.com/igraph/python-igraph/compare/0.10.8...0.11.0 +[0.10.8]: https://github.com/igraph/python-igraph/compare/0.10.7...0.10.8 +[0.10.7]: https://github.com/igraph/python-igraph/compare/0.10.6...0.10.7 +[0.10.6]: https://github.com/igraph/python-igraph/compare/0.10.5...0.10.6 +[0.10.5]: https://github.com/igraph/python-igraph/compare/0.10.4...0.10.5 +[0.10.4]: https://github.com/igraph/python-igraph/compare/0.10.3...0.10.4 +[0.10.3]: https://github.com/igraph/python-igraph/compare/0.10.2...0.10.3 [0.10.2]: https://github.com/igraph/python-igraph/compare/0.10.1...0.10.2 [0.10.1]: https://github.com/igraph/python-igraph/compare/0.10.0...0.10.1 [0.10.0]: https://github.com/igraph/python-igraph/compare/0.9.11...0.10.0 diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000..e803bfa79 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,53 @@ +# This CITATION.cff file was generated with cffinit. +# Visit https://bit.ly/cffinit to generate yours today! + +cff-version: 1.2.0 +title: igraph +message: >- + If you use igraph, please cite it using the + metadata from this file. +type: software +authors: + - given-names: Gábor + family-names: Csárdi + orcid: 'https://orcid.org/0000-0001-7098-9676' + - given-names: Tamás + family-names: Nepusz + orcid: 'https://orcid.org/0000-0002-1451-338X' + - given-names: Szabolcs + family-names: Horvát + orcid: 'https://orcid.org/0000-0002-3100-523X' + - given-names: Vincent Antonio + family-names: Traag + orcid: 'https://orcid.org/0000-0003-3170-3879' + - given-names: Fabio + family-names: Zanini + orcid: 'https://orcid.org/0000-0001-7097-8539' + - given-names: Daniel + family-names: Noom +repository-code: 'https://github.com/igraph/python-igraph' +url: 'https://igraph.org' +abstract: >- + igraph is a C library for complex network analysis and + graph theory, with emphasis on efficiency, portability and + ease of use. +keywords: + - network analysis + - graph theory +license: GPL-2.0-or-later +version: 0.10.5 +date-released: '2023-07-01' +preferred-citation: + type: article + authors: + - given-names: Gábor + family-names: Csárdi + orcid: 'https://orcid.org/0000-0001-7098-9676' + - given-names: Tamás + family-names: Nepusz + orcid: 'https://orcid.org/0000-0002-1451-338X' + journal: "InterJournal, Complex Systems" + start: 1695 # First page number + title: "The igraph software package for complex network research" + year: 2006 + type: article diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 75652838e..d22d5bd6f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -6,82 +6,101 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Tamás Nepusz

💻

Fabio Zanini

💻

Kevin Zhu

💻

Gábor Csárdi

💻

Szabolcs Horvát

💻

Vincent Traag

💻

deeenes

💻

Seungoh Han

💻

Artem V L

💻

Yesung(Isaac) Lee

💻

John Boy

💻

Casper da Costa-Luis

💻

Alberto Alcolea

💻

Árpád Horváth

💻

ebraminio

💻

Fabian Witter

💻

Jan Katins

💻

Nick Eubank

💻

Peter Scott

💻

Sriram-Pattabiraman

💻

Sviatoslav

💻

Ah-Young Nho

💻

Frederik Harwath

💻

Navid Dianati

💻

abe-winter

💻

Alejandro Rivero

💻

Ariki

💻

Casper van Elteren

💻

Charles Tapley Hoyt

💻

Christoph Gohlke

💻

Christopher Falter

💻

FredInChina

💻

Friso van Vollenhoven

💻

Gabor Szarnyas

💻

Gao Fangshu

💻

Grzegorz Chilczuk

💻

Gwyn Ciesla

💻

Hong Xu

💻

Jay Smith

💻

MapleCCC

💻

Marco Köpcke

💻

Markus Elfring

💻

Martino Mensio

💻

Matas

💻

Mike Lissner

💻

Philipp A.

💻

Puneetha Pai

💻

S Murthy

💻

Scott Gigante

💻

Thierry Thomas

💻

Willem van den Boom

💻

Yisu Remy Wang

💻

YY Ahn

💻

kmankinen

💻

odidev

💻

sombreslames

💻

szcf-weiya

💻

tristanlatr

💻
Tamás Nepusz
Tamás Nepusz

💻
Fabio Zanini
Fabio Zanini

💻
Kevin Zhu
Kevin Zhu

💻
Gábor Csárdi
Gábor Csárdi

💻
Szabolcs Horvát
Szabolcs Horvát

💻
Vincent Traag
Vincent Traag

💻
deeenes
deeenes

💻
Seungoh Han
Seungoh Han

💻
Artem V L
Artem V L

💻
Yesung(Isaac) Lee
Yesung(Isaac) Lee

💻
John Boy
John Boy

💻
Casper da Costa-Luis
Casper da Costa-Luis

💻
Alberto Alcolea
Alberto Alcolea

💻
Árpád Horváth
Árpád Horváth

💻
ebraminio
ebraminio

💻
Fabian Witter
Fabian Witter

💻
Jan Katins
Jan Katins

💻
Nick Eubank
Nick Eubank

💻
Peter Scott
Peter Scott

💻
Sriram-Pattabiraman
Sriram-Pattabiraman

💻
Sviatoslav
Sviatoslav

💻
Ah-Young Nho
Ah-Young Nho

💻
Frederik Harwath
Frederik Harwath

💻
Navid Dianati
Navid Dianati

💻
abe-winter
abe-winter

💻
Alejandro Rivero
Alejandro Rivero

💻
Ariki
Ariki

💻
Casper van Elteren
Casper van Elteren

💻
Charles Tapley Hoyt
Charles Tapley Hoyt

💻
Christoph Gohlke
Christoph Gohlke

💻
Christopher Falter
Christopher Falter

💻
FredInChina
FredInChina

💻
Friso van Vollenhoven
Friso van Vollenhoven

💻
Gabor Szarnyas
Gabor Szarnyas

💻
Gao Fangshu
Gao Fangshu

💻
Grzegorz Chilczuk
Grzegorz Chilczuk

💻
Gwyn Ciesla
Gwyn Ciesla

💻
Hong Xu
Hong Xu

💻
Jay Smith
Jay Smith

💻
MapleCCC
MapleCCC

💻
Marco Köpcke
Marco Köpcke

💻
Markus Elfring
Markus Elfring

💻
Martino Mensio
Martino Mensio

💻
Matas
Matas

💻
Mike Lissner
Mike Lissner

💻
Philipp A.
Philipp A.

💻
Puneetha Pai
Puneetha Pai

💻
S Murthy
S Murthy

💻
Scott Gigante
Scott Gigante

💻
Thierry Thomas
Thierry Thomas

💻
Willem van den Boom
Willem van den Boom

💻
Yisu Remy Wang
Yisu Remy Wang

💻
YY Ahn
YY Ahn

💻
kmankinen
kmankinen

💻
odidev
odidev

💻
sombreslames
sombreslames

💻
szcf-weiya
szcf-weiya

💻
tristanlatr
tristanlatr

💻
JDPowell648
JDPowell648

📖
k.h.lai
k.h.lai

💻
Anton Grübel
Anton Grübel

💻
flange-ipb
flange-ipb

💻
Paul m. p. Peny
Paul m. p. Peny

💻
David R. Connell
David R. Connell

💻
Rodrigo Monteiro de Moraes de Arruda Falcão
Rodrigo Monteiro de Moraes de Arruda Falcão

💻
Kreijstal
Kreijstal

💻
Michael Schneider
Michael Schneider

💻
Thomas Krijnen
Thomas Krijnen

💻
Tim Bernhard
Tim Bernhard

💻
Bea Márton
Bea Márton

💻
Sanat Kumar Gupta
Sanat Kumar Gupta

💻
@@ -89,4 +108,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! \ No newline at end of file +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/MANIFEST.in b/MANIFEST.in index 1a25d4486..39e2ee9fe 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,21 @@ +prune docker +prune .git +prune .github + include src/_igraph/*.h include MANIFEST.in -include scripts/mkdoc.sh +include scripts/*.sh +include scripts/*.py include tests/*.py +include CHANGELOG.md +include CONTRIBUTORS.md +include CITATION.cff + graft vendor/source/igraph +graft doc +prune doc/html +prune doc/source/tutorials + +global-exclude .dockerignore .DS_Store .gitattributes .gitignore .gitmodules diff --git a/README.md b/README.md index c24867860..1f7162788 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,10 @@ [![Build and test with tox](https://github.com/igraph/python-igraph/actions/workflows/build.yml/badge.svg)](https://github.com/igraph/python-igraph/actions/workflows/build.yml) -[![PyPI pyversions](https://img.shields.io/badge/python-3.7%20%7C%203.8%20%7C%203.9%20%7C%203.10-blue)](https://pypi.python.org/pypi/igraph) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/igraph)](https://pypi.python.org/pypi/igraph) [![PyPI wheels](https://img.shields.io/pypi/wheel/igraph.svg)](https://pypi.python.org/pypi/igraph) [![Documentation Status](https://readthedocs.org/projects/igraph/badge/?version=latest)](https://igraph.readthedocs.io/) -Python interface for the igraph library ---------------------------------------- +# Python interface for the igraph library igraph is a library for creating and manipulating graphs. It is intended to be as powerful (ie. fast) as possible to enable the @@ -21,7 +20,13 @@ on [our old website](https://igraph.org/python/versions/0.10.1/). igraph is a collaborative work of many people from all around the world — see the [list of contributors here](./CONTRIBUTORS.md). -## Installation from PyPI +## Citation + +If you use igraph in your research, please cite + +> Csardi, G., & Nepusz, T. (2006). The igraph software package for complex network research. InterJournal, Complex Systems, 1695. + +# Installation We aim to provide wheels on PyPI for most of the stock Python versions; typically at least the three most recent minor releases from Python 3.x. @@ -34,7 +39,7 @@ pip install igraph See details in [Installing Python Modules](https://docs.python.org/3/installing/). -### Installation from source with pip on Debian / Ubuntu and derivatives +## Installation from source with pip on Debian / Ubuntu and derivatives If you need to compile igraph from source for some reason, you need to install some dependencies first: @@ -52,14 +57,15 @@ pip install igraph This should compile the C core of igraph as well as the Python extension automatically. -### Installation from source on Windows +## Installation from source on Windows It is now also possible to compile `igraph` from source under Windows for Python 3.7 and later. Make sure that you have Microsoft Visual Studio 2015 or later installed, and of course Python 3.7 or later. First extract the source to a suitable directory. If you launch the Developer command prompt and navigate to the directory where you extracted the source code, you should be able to build -and install igraph using `python setup.py install` +and install igraph using `pip install .`, assuming that you have `pip` +installed in your Python environment. You may need to set the architecture that you are building on explicitly by setting the environment variable @@ -72,7 +78,11 @@ Also, when building in MSYS2, you need to set the `SETUPTOOLS_USE_DISTUTILS` environment variable to `stdlib`; this is because MSYS2 uses a patched version of `distutils` that conflicts with `setuptools >= 60.0`. -#### Enabling GraphML +> [!TIP] +> You need the following packages: +> `$MINGW_PACKAGE_PREFIX-python-pip $MINGW_PACKAGE_PREFIX-python-setuptools $MINGW_PACKAGE_PREFIX-cc $MINGW_PACKAGE_PREFIX-cmake` + +### Enabling GraphML By default, GraphML is disabled, because `libxml2` is not available on Windows in the standard installation. You can install `libxml2` on Windows using @@ -105,17 +115,17 @@ set IGRAPH_EXTRA_LIBRARIES=libxml2,lzma,zlib,iconv,charset set IGRAPH_EXTRA_DYNAMIC_LIBRARIES: wsock32,ws2_32 ``` -You can now build and install `igraph` again by simply running `python -setup.py build`. Please make sure to use a clean source tree, if you built -previously without GraphML, it will not update the build. +You can now build and install `igraph` again by simply running `pip install .`. +Please make sure to use a clean source tree, if you built previously without +GraphML, it will not update the build. -### Linking to an existing igraph installation +## Linking to an existing igraph installation The source code of the Python package includes the source code of the matching igraph version that the Python interface should compile against. However, if you want to link the Python interface to a custom installation of the C core -that has already been compiled and installed on your system, you can ask -`setup.py` to use the pre-compiled version. This option requires that your +that has already been compiled and installed on your system, you can ask our +build system to use the pre-compiled version. This option requires that your custom installation of igraph is discoverable with `pkg-config`. First, check whether `pkg-config` can tell you the required compiler and linker flags for igraph: @@ -135,15 +145,14 @@ IGRAPH_USE_PKG_CONFIG=1 pip install igraph ``` Alternatively, if you have already downloaded and extracted the source code -of igraph, you can run `setup.py` directly: +of igraph, you can run `pip install` on the source tree directly: ```bash -IGRAPH_USE_PKG_CONFIG=1 python setup.py build -IGRAPH_USE_PKG_CONFIG=1 python setup.py install +IGRAPH_USE_PKG_CONFIG=1 pip install . ``` (Note that you need the `IGRAPH_USE_PKG_CONFIG=1` environment variable -for both invocations, otherwise the call to `setup.py install` would still +for both invocations, otherwise the call to `pip install` would still build the vendored C core instead of linking to an existing installation). This option is primarily intended for package maintainers in Linux @@ -153,8 +162,16 @@ the packaged igraph library instead of bringing its own copy. It is also useful on macOS if you want to link to the igraph library installed from Homebrew. -Due to the lack of support of `pkg-config` on Windows, it is currently not -possible to build against an external library on Windows. +Due to the lack of support of `pkg-config` on MSVC, it is currently not +possible to build against an external library on MSVC. + +In case you are already using a MSYS2/[MinGW](https://www.mingw-w64.org/) and already have +[mingw-w64-igraph](https://packages.msys2.org/base/mingw-w64-igraph) installed, +simply type: +``` +IGRAPH_USE_PKG_CONFIG=1 SETUPTOOLS_USE_DISTUTILS=stdlib pip install igraph +``` +to build. **Warning:** the Python interface is guaranteed to work only with the same version of the C core that is vendored inside the `vendor/source/igraph` @@ -186,8 +203,9 @@ pip install git+https://github.com/igraph/python-igraph This automatically fetches the development version from the repository, builds the package and installs it. By default, this will install the Python interface -from the `master` branch, which is used as the basis for the development of the -current release series. Unstable and breaking changes are being made in the `develop` branch. You can install this similarly by doing +from the `main` branch, which is used as the basis for the development of the +current release series. Unstable and breaking changes are being made in the +`develop` branch. You can install this similarly by doing ```bash pip install git+https://github.com/igraph/python-igraph@develop @@ -196,10 +214,9 @@ pip install git+https://github.com/igraph/python-igraph@develop In addition to `git`, the installation of the development version requires some additional dependencies, read further below for details. -For more information about installing directly from `git` using `pip` see +For more information about installing directly from `git` using `pip` see https://pip.pypa.io/en/stable/topics/vcs-support/#git. - Alternatively, you can clone this repository locally. This repository contains a matching version of the C core of `igraph` as a git submodule. In order to install the development version from source, you need to instruct git to check @@ -219,17 +236,20 @@ sudo apt install bison flex On macOS you can install these from Homebrew or MacPorts. On Windows you can install `winflexbison3` from Chocolatey. -Then, running the setup script should work if you have a C compiler and the -necessary build dependencies (see also the previous section): +Then you can install the package directly with `pip` (see also the previous section): ```bash -python setup.py build +pip install . ``` -You can install it using +If you would like to create a source distribution or a Python wheel instead of +installing the module directly in your Python environment, use a standard build +frontend like [build](https://pypa-build.readthedocs.io/en/stable/). If you +use [pipx](https://pypa.github.io/pipx/) to isolate command-line Python tools +in their own separate virtualenvs, you can simply run: ```bash -python setup.py install +pipx run build ``` ### Running unit tests @@ -241,7 +261,18 @@ with the built-in `unittest` module: python -m unittest ``` -## Contributing +Note that unit tests have additional dependencies like NumPy, PIL or +`matplotlib`. The unit test suite will try to do its best to skip tests +requiring external dependencies, but if you want to make sure that all the unit +tests are executed, either use `tox` (which will take care of installing the +test dependencies in a virtualenv), or install the module with the `test` +extras: + +```bash +pip install '.[test]' +``` + +# Contributing Contributions to `igraph` are welcome! @@ -251,34 +282,35 @@ that you would like to see included in the main tree, open a PR on this repo. To start developing `igraph`, follow the steps above about installing the development version. Make sure that you do so by cloning the repository locally so that you are able to make changes. -For easier development, you can install `igraph` in development mode so your changes in the Python source -code are picked up automatically by Python: +For easier development, you can install `igraph` in "editable" (i.e. +development) mode so your changes in the Python source code are picked up +automatically by Python: ```bash -python setup.py develop +pip install -e . ``` Changes that you make to the Python code do not need any extra action. However, if you adjust the source code of the C extension, you need to rebuild it by running -`python setup.py develop` again. Compilation of the C core of `igraph` is +`pip install -e .` again. Compilation of the C core of `igraph` is cached in ``vendor/build`` and ``vendor/install`` so subsequent builds are much faster than the first one as the C core does not need to be recompiled. -## Notes +# Notes -### Supported Python versions +## Supported Python versions We aim to keep up with the development cycle of Python and support all official Python versions that have not reached their end of life yet. Currently this -means that we support Python 3.7 to 3.10, inclusive. Please refer to [this -page](https://devguide.python.org/#branchstatus) for the status of Python +means that we support Python 3.9 to 3.13, inclusive. Please refer to [this +page](https://devguide.python.org/versions/) for the status of Python branches and let us know if you encounter problems with `igraph` on any of the non-EOL Python versions. Continuous integration tests are regularly executed on all non-EOL Python branches. -### PyPy +## PyPy This version of igraph is compatible with [PyPy](http://pypy.org/) and is regularly tested on [PyPy](http://pypy.org/) with ``tox``. However, the @@ -294,4 +326,3 @@ There are also some subtle differences between the CPython and PyPy versions: - ``GraphBase`` is hashable and iterable in PyPy but not in CPython. Since ``GraphBase`` is internal anyway, this is likely to stay this way. - diff --git a/doc/examples_sphinx-gallery/articulation_points.py b/doc/examples_sphinx-gallery/articulation_points.py index 2b92b3704..6492f1f6f 100644 --- a/doc/examples_sphinx-gallery/articulation_points.py +++ b/doc/examples_sphinx-gallery/articulation_points.py @@ -8,6 +8,7 @@ This example shows how to compute and visualize the `articulation points `_ in a graph using :meth:`igraph.GraphBase.articulation_points`. For an example on bridges instead, see :ref:`tutorials-bridges`. """ + import igraph as ig import matplotlib.pyplot as plt @@ -25,14 +26,14 @@ # Finally, we can plot the graph fig, ax = plt.subplots() ig.plot( - g, - target=ax, - vertex_size=0.3, + g, + target=ax, + vertex_size=30, vertex_color="lightblue", vertex_label=range(g.vcount()), - vertex_frame_color = ["red" if v in articulation_points else "black" for v in g.vs], - vertex_frame_width = [3 if v in articulation_points else 1 for v in g.vs], + vertex_frame_color=["red" if v in articulation_points else "black" for v in g.vs], + vertex_frame_width=[3 if v in articulation_points else 1 for v in g.vs], edge_width=0.8, - edge_color='gray' + edge_color="gray", ) plt.show() diff --git a/doc/examples_sphinx-gallery/betweenness.py b/doc/examples_sphinx-gallery/betweenness.py index a9e568e70..7c52bdb08 100644 --- a/doc/examples_sphinx-gallery/betweenness.py +++ b/doc/examples_sphinx-gallery/betweenness.py @@ -24,14 +24,14 @@ # :meth:`igraph.utils.rescale` to rescale the betweennesses in the interval # ``[0, 1]``. def plot_betweenness(g, vertex_betweenness, edge_betweenness, ax, cax1, cax2): - '''Plot vertex/edge betweenness, with colorbars + """Plot vertex/edge betweenness, with colorbars Args: g: the graph to plot. ax: the Axes for the graph cax1: the Axes for the vertex betweenness colorbar cax2: the Axes for the edge betweenness colorbar - ''' + """ # Rescale betweenness to be between 0.0 and 1.0 scaled_vertex_betweenness = ig.rescale(vertex_betweenness, clamp=True) @@ -45,7 +45,7 @@ def plot_betweenness(g, vertex_betweenness, edge_betweenness, ax, cax1, cax2): # Plot graph g.vs["color"] = [cmap1(betweenness) for betweenness in scaled_vertex_betweenness] - g.vs["size"] = ig.rescale(vertex_betweenness, (0.1, 0.5)) + g.vs["size"] = ig.rescale(vertex_betweenness, (10, 50)) g.es["color"] = [cmap2(betweenness) for betweenness in scaled_edge_betweenness] g.es["width"] = ig.rescale(edge_betweenness, (0.5, 1.0)) ig.plot( @@ -58,8 +58,8 @@ def plot_betweenness(g, vertex_betweenness, edge_betweenness, ax, cax1, cax2): # Color bars norm1 = ScalarMappable(norm=Normalize(0, max(vertex_betweenness)), cmap=cmap1) norm2 = ScalarMappable(norm=Normalize(0, max(edge_betweenness)), cmap=cmap2) - plt.colorbar(norm1, cax=cax1, orientation="horizontal", label='Vertex Betweenness') - plt.colorbar(norm2, cax=cax2, orientation="horizontal", label='Edge Betweenness') + plt.colorbar(norm1, cax=cax1, orientation="horizontal", label="Vertex Betweenness") + plt.colorbar(norm2, cax=cax2, orientation="horizontal", label="Edge Betweenness") # %% @@ -83,7 +83,7 @@ def plot_betweenness(g, vertex_betweenness, edge_betweenness, ax, cax1, cax2): fig, axs = plt.subplots( 3, 2, figsize=(7, 6), - gridspec_kw=dict(height_ratios=(20, 1, 1)), + gridspec_kw={"height_ratios": (20, 1, 1)}, ) plot_betweenness(g1, vertex_betweenness1, edge_betweenness1, *axs[:, 0]) plot_betweenness(g2, vertex_betweenness2, edge_betweenness2, *axs[:, 1]) diff --git a/doc/examples_sphinx-gallery/bipartite_matching.py b/doc/examples_sphinx-gallery/bipartite_matching.py index dd7885b07..1046e1322 100644 --- a/doc/examples_sphinx-gallery/bipartite_matching.py +++ b/doc/examples_sphinx-gallery/bipartite_matching.py @@ -7,6 +7,7 @@ This example demonstrates an efficient way to find and visualise a maximum biparite matching using :meth:`igraph.Graph.maximum_bipartite_matching`. """ + import igraph as ig import matplotlib.pyplot as plt @@ -16,7 +17,7 @@ # - nodes 5-8 to the other side g = ig.Graph.Bipartite( [0, 0, 0, 0, 0, 1, 1, 1, 1], - [(0, 5), (1, 6), (1, 7), (2, 5), (2, 8), (3, 6), (4, 5), (4, 6)] + [(0, 5), (1, 6), (1, 7), (2, 5), (2, 8), (3, 6), (4, 5), (4, 6)], ) # %% @@ -45,7 +46,7 @@ g, target=ax, layout=g.layout_bipartite(), - vertex_size=0.4, + vertex_size=30, vertex_label=range(g.vcount()), vertex_color="lightblue", edge_width=[3 if e.target == matching.match_of(e.source) else 1.0 for e in g.es], diff --git a/doc/examples_sphinx-gallery/bipartite_matching_maxflow.py b/doc/examples_sphinx-gallery/bipartite_matching_maxflow.py index 6164e0e47..eec39a81b 100644 --- a/doc/examples_sphinx-gallery/bipartite_matching_maxflow.py +++ b/doc/examples_sphinx-gallery/bipartite_matching_maxflow.py @@ -9,6 +9,7 @@ .. note:: :meth:`igraph.Graph.maximum_bipartite_matching` is usually a better way to find the maximum bipartite matching. For a demonstration on how to use that method instead, check out :ref:`tutorials-bipartite-matching`. """ + import igraph as ig import matplotlib.pyplot as plt @@ -17,7 +18,7 @@ g = ig.Graph( 9, [(0, 4), (0, 5), (1, 4), (1, 6), (1, 7), (2, 5), (2, 7), (2, 8), (3, 6), (3, 7)], - directed=True + directed=True, ) # %% @@ -59,9 +60,9 @@ g, target=ax, layout=layout, - vertex_size=0.4, + vertex_size=30, vertex_label=range(g.vcount()), vertex_color=["lightblue" if i < 9 else "orange" for i in range(11)], - edge_width=[1.0 + flow.flow[i] for i in range(g.ecount())] + edge_width=[1.0 + flow.flow[i] for i in range(g.ecount())], ) plt.show() diff --git a/doc/examples_sphinx-gallery/bridges.py b/doc/examples_sphinx-gallery/bridges.py index ba821e88b..08dc47d48 100644 --- a/doc/examples_sphinx-gallery/bridges.py +++ b/doc/examples_sphinx-gallery/bridges.py @@ -7,14 +7,15 @@ This example shows how to compute and visualize the `bridges `_ in a graph using :meth:`igraph.GraphBase.bridges`. For an example on articulation points instead, see :ref:`tutorials-articulation-points`. """ + import igraph as ig import matplotlib.pyplot as plt # %% # Let's start with a simple example. We begin by constructing a graph that # includes a few bridges: -g = ig.Graph(14, [(0, 1), (1, 2), (2, 3), (0, 3), (0, 2), (1, 3), (3, 4), - (4, 5), (5, 6), (6, 4), (6, 7), (7, 8), (7, 9), (9, 10), (10 ,11), +g = ig.Graph(14, [(0, 1), (1, 2), (2, 3), (0, 3), (0, 2), (1, 3), (3, 4), + (4, 5), (5, 6), (6, 4), (6, 7), (7, 8), (7, 9), (9, 10), (10 ,11), (11 ,7), (7, 10), (8, 9), (8, 10), (5, 12), (12, 13)]) # %% @@ -33,11 +34,11 @@ # Finally, we plot the graph using that emphasis: fig, ax = plt.subplots() ig.plot( - g, - target=ax, - vertex_size=0.3, + g, + target=ax, + vertex_size=30, vertex_color="lightblue", - vertex_label=range(g.vcount()) + vertex_label=range(g.vcount()), ) plt.show() @@ -48,8 +49,8 @@ # %% # As before, we begin by constructing the graph: -g = ig.Graph(14, [(0, 1), (1, 2), (2, 3), (0, 3), (0, 2), (1, 3), (3, 4), - (4, 5), (5, 6), (6, 4), (6, 7), (7, 8), (7, 9), (9, 10), (10 ,11), +g = ig.Graph(14, [(0, 1), (1, 2), (2, 3), (0, 3), (0, 2), (1, 3), (3, 4), + (4, 5), (5, 6), (6, 4), (6, 7), (7, 8), (7, 9), (9, 10), (10 ,11), (11 ,7), (7, 10), (8, 9), (8, 10), (5, 12), (12, 13)]) # %% @@ -67,15 +68,14 @@ # Finally, we can plot the graph: fig, ax = plt.subplots() ig.plot( - g, - target=ax, - vertex_size=0.3, + g, + target=ax, + vertex_size=30, vertex_color="lightblue", vertex_label=range(g.vcount()), - edge_background="#FFF0", # transparent background color - edge_align_label=True, # make sure labels are aligned with the edge + edge_background="#FFF0", # transparent background color + edge_align_label=True, # make sure labels are aligned with the edge edge_label=g.es["label"], - edge_label_color="red" + edge_label_color="red", ) plt.show() - diff --git a/doc/examples_sphinx-gallery/cluster_contraction.py b/doc/examples_sphinx-gallery/cluster_contraction.py index f39e71d5d..fc02fc293 100644 --- a/doc/examples_sphinx-gallery/cluster_contraction.py +++ b/doc/examples_sphinx-gallery/cluster_contraction.py @@ -7,12 +7,13 @@ This example shows how to find the communities in a graph, then contract each community into a single node using :class:`igraph.clustering.VertexClustering`. For this tutorial, we'll use the *Donald Knuth's Les Miserables Network*, which shows the coapperances of characters in the novel *Les Miserables*. """ + import igraph as ig import matplotlib.pyplot as plt # %% # We begin by load the graph from file. The file containing this network can be -# downloaded `here `_. +# downloaded `here `_. g = ig.load("./lesmis/lesmis.gml") # %% @@ -55,7 +56,7 @@ target=ax1, mark_groups=True, palette=palette1, - vertex_size=0.1, + vertex_size=15, edge_width=0.5, ) fig1.set_size_inches(20, 20) @@ -67,8 +68,8 @@ # for each node in the original graph: layout = g.layout_kamada_kawai() g.vs["x"], g.vs["y"] = list(zip(*layout)) -g.vs["size"] = 1 -g.es["size"] = 1 +g.vs["size"] = 15 +g.es["size"] = 15 # %% # Then we can generate the cluster graph that compresses each community into a @@ -106,7 +107,10 @@ # Finally, we can assign colors to the clusters and plot the cluster graph, # including a legend to make things clear: palette2 = ig.GradientPalette("gainsboro", "black") -g.es["color"] = [palette2.get(int(i)) for i in ig.rescale(cluster_graph.es["size"], (0, 255), clamp=True)] +g.es["color"] = [ + palette2.get(int(i)) + for i in ig.rescale(cluster_graph.es["size"], (0, 255), clamp=True) +] fig2, ax2 = plt.subplots() ig.plot( @@ -114,7 +118,7 @@ target=ax2, palette=palette1, # set a minimum size on vertex_size, otherwise vertices are too small - vertex_size=[max(0.2, size / 20) for size in cluster_graph.vs["size"]], + vertex_size=[max(20, size) for size in cluster_graph.vs["size"]], edge_color=g.es["color"], edge_width=0.8, ) @@ -123,7 +127,8 @@ legend_handles = [] for i in range(num_communities): handle = ax2.scatter( - [], [], + [], + [], s=100, facecolor=palette1.get(i), edgecolor="k", @@ -133,7 +138,7 @@ ax2.legend( handles=legend_handles, - title='Community:', + title="Community:", bbox_to_anchor=(0, 1.0), bbox_transform=ax2.transAxes, ) diff --git a/doc/examples_sphinx-gallery/complement.py b/doc/examples_sphinx-gallery/complement.py index 4436ae372..b4f2f17a0 100644 --- a/doc/examples_sphinx-gallery/complement.py +++ b/doc/examples_sphinx-gallery/complement.py @@ -7,6 +7,7 @@ This example shows how to generate the `complement graph `_ of a graph (sometimes known as the anti-graph) using :meth:`igraph.GraphBase.complementer`. """ + import igraph as ig import matplotlib.pyplot as plt import random @@ -49,14 +50,14 @@ layout="circle", vertex_color="black", ) -axs[0, 0].set_title('Original graph') +axs[0, 0].set_title("Original graph") ig.plot( g2, target=axs[0, 1], layout="circle", vertex_color="black", ) -axs[0, 1].set_title('Complement graph') +axs[0, 1].set_title("Complement graph") ig.plot( g_full, @@ -64,12 +65,12 @@ layout="circle", vertex_color="black", ) -axs[1, 0].set_title('Union graph') +axs[1, 0].set_title("Union graph") ig.plot( g_empty, target=axs[1, 1], layout="circle", vertex_color="black", ) -axs[1, 1].set_title('Complement of union graph') +axs[1, 1].set_title("Complement of union graph") plt.show() diff --git a/doc/examples_sphinx-gallery/configuration.py b/doc/examples_sphinx-gallery/configuration.py index fb0c07483..4e9c077eb 100644 --- a/doc/examples_sphinx-gallery/configuration.py +++ b/doc/examples_sphinx-gallery/configuration.py @@ -7,6 +7,7 @@ This example shows how to use igraph's :class:`configuration instance ` to set default igraph settings. This is useful for setting global settings so that they don't need to be explicitly stated at the beginning of every igraph project you work on. """ + import igraph as ig import matplotlib.pyplot as plt import random @@ -18,16 +19,16 @@ ig.config["plotting.palette"] = "rainbow" # %% -# Then, we save them. By default, ``ig.config.save()`` will save files to -# ``~/.igraphrc`` on Linux and Max OS X systems, or in -# ``%USERPROFILE%\.igraphrc`` for Windows systems: -ig.config.save() +# The updated configuration affects only the current session. Optionally, it +# can be saved using ``ig.config.save()``. By default, this function writes the +# configuration to ``~/.igraphrc`` on Linux and Max OS X systems, and in +# ``%USERPROFILE%\.igraphrc`` on Windows systems. # %% -# The code above only needs to be run once (to store the new config options -# into the ``.igraphrc`` file). Whenever you use igraph and this file exists, -# igraph will read its content and use those options as defaults. For -# example, let's create and plot a new graph to demonstrate: +# The configuration only needs to be saved to `.igraphrc` once, and it will +# be automatically used in all future sessions. Whenever you use igraph and +# this file exists, igraph will read its content and use those options as +# defaults. For example, let's create and plot a new graph to demonstrate: random.seed(1) g = ig.Graph.Barabasi(n=100, m=1) @@ -40,7 +41,7 @@ # %% # Finally, we can plot the graph. You will notice that even though we did not # create a dedicated figure and axes, matplotlib is now used by default: -ig.plot(g, vertex_color=colors, vertex_size=1, edge_width=0.3) +ig.plot(g, vertex_color=colors, vertex_size=15, edge_width=0.3) plt.show() # %% diff --git a/doc/examples_sphinx-gallery/connected_components.py b/doc/examples_sphinx-gallery/connected_components.py index e85869cd5..33c341fee 100644 --- a/doc/examples_sphinx-gallery/connected_components.py +++ b/doc/examples_sphinx-gallery/connected_components.py @@ -7,6 +7,7 @@ This example demonstrates how to visualise the connected components in a graph using :meth:`igraph.GraphBase.connected_components`. """ + import igraph as ig import matplotlib.pyplot as plt import random @@ -21,7 +22,7 @@ # %% # Now we can cluster the graph into weakly connected components, i.e. subgraphs # that have no edges connecting them to one another: -components = g.connected_components(mode='weak') +components = g.connected_components(mode="weak") # %% # Finally, we can visualize the distinct connected components of the graph: @@ -30,7 +31,7 @@ components, target=ax, palette=ig.RainbowPalette(), - vertex_size=0.07, + vertex_size=7, vertex_color=list(map(int, ig.rescale(components.membership, (0, 200), clamp=True))), edge_width=0.7 ) diff --git a/doc/examples_sphinx-gallery/delaunay-triangulation.py b/doc/examples_sphinx-gallery/delaunay-triangulation.py index 8f95b6e75..3a25eebe1 100644 --- a/doc/examples_sphinx-gallery/delaunay-triangulation.py +++ b/doc/examples_sphinx-gallery/delaunay-triangulation.py @@ -8,6 +8,7 @@ This example demonstrates how to calculate the `Delaunay triangulation `_ of an input graph. We start by generating a set of points on a 2D grid using random ``numpy`` arrays and a graph with those vertex coordinates and no edges. """ + import numpy as np from scipy.spatial import Delaunay import igraph as ig @@ -20,8 +21,8 @@ np.random.seed(0) x, y = np.random.rand(2, 30) g = ig.Graph(30) -g.vs['x'] = x -g.vs['y'] = y +g.vs["x"] = x +g.vs["y"] = y # %% # Because we already set the `x` and `y` vertex attributes, we can use @@ -56,7 +57,7 @@ g, layout=layout, target=ax, - vertex_size=0.04, + vertex_size=4, vertex_color="lightblue", edge_width=0.8 ) @@ -90,7 +91,7 @@ g, layout=layout, target=ax, - vertex_size=0.0, + vertex_size=0, edge_width=0.2, edge_color="white", ) diff --git a/doc/examples_sphinx-gallery/erdos_renyi.py b/doc/examples_sphinx-gallery/erdos_renyi.py index cb3ddf530..aeb808992 100644 --- a/doc/examples_sphinx-gallery/erdos_renyi.py +++ b/doc/examples_sphinx-gallery/erdos_renyi.py @@ -12,6 +12,7 @@ We generate two graphs of each, so we can confirm that our graph generator is truly random. """ + import igraph as ig import matplotlib.pyplot as plt import random @@ -48,33 +49,11 @@ # differences: fig, axs = plt.subplots(2, 2) # Probability -ig.plot( - g1, - target=axs[0, 0], - layout="circle", - vertex_color="lightblue" -) -ig.plot( - g2, - target=axs[0, 1], - layout="circle", - vertex_color="lightblue" -) -axs[0, 0].set_ylabel('Probability') +ig.plot(g1, target=axs[0, 0], layout="circle", vertex_color="lightblue") +ig.plot(g2, target=axs[0, 1], layout="circle", vertex_color="lightblue") +axs[0, 0].set_ylabel("Probability") # N edges -ig.plot( - g3, - target=axs[1, 0], - layout="circle", - vertex_color="lightblue", - vertex_size=0.15 -) -ig.plot( - g4, - target=axs[1, 1], - layout="circle", - vertex_color="lightblue", - vertex_size=0.15 -) -axs[1, 0].set_ylabel('N. edges') +ig.plot(g3, target=axs[1, 0], layout="circle", vertex_color="lightblue", vertex_size=15) +ig.plot(g4, target=axs[1, 1], layout="circle", vertex_color="lightblue", vertex_size=15) +axs[1, 0].set_ylabel("N. edges") plt.show() diff --git a/doc/examples_sphinx-gallery/generate_dag.py b/doc/examples_sphinx-gallery/generate_dag.py new file mode 100644 index 000000000..1565a59ed --- /dev/null +++ b/doc/examples_sphinx-gallery/generate_dag.py @@ -0,0 +1,46 @@ +""" + +.. _tutorials-dag: + +====================== +Directed Acyclic Graph +====================== + +This example demonstrates how to create a random directed acyclic graph (DAG), which is useful in a number of contexts including for Git commit history. +""" + +import igraph as ig +import matplotlib.pyplot as plt +import random + + +# %% +# First, we set a random seed for reproducibility. +random.seed(0) + +# %% +# First, we generate a random undirected graph with a fixed number of edges, without loops. +g = ig.Graph.Erdos_Renyi(n=15, m=30, directed=False, loops=False) + +# %% +# Then we convert it to a DAG *in place*. This method samples DAGs with a given number of edges and vertices uniformly. +g.to_directed(mode="acyclic") + +# %% +# We can print out a summary of the DAG. +ig.summary(g) + + +# %% +# Finally, we can plot the graph using the Sugiyama layout from :meth:`igraph.Graph.layout_sugiyama`: +fig, ax = plt.subplots() +ig.plot( + g, + target=ax, + layout="sugiyama", + vertex_size=15, + vertex_color="grey", + edge_color="#222", + edge_width=1, +) +plt.show() diff --git a/doc/examples_sphinx-gallery/isomorphism.py b/doc/examples_sphinx-gallery/isomorphism.py index dd1e130b8..57c6034f4 100644 --- a/doc/examples_sphinx-gallery/isomorphism.py +++ b/doc/examples_sphinx-gallery/isomorphism.py @@ -7,6 +7,7 @@ This example shows how to check for `isomorphism `_ between small graphs using :meth:`igraph.GraphBase.isomorphic`. """ + import igraph as ig import matplotlib.pyplot as plt @@ -44,7 +45,7 @@ visual_style = { "vertex_color": "lightblue", "vertex_label": [0, 1, 2, 3, 4], - "vertex_size": 0.4, + "vertex_size": 25, } fig, axs = plt.subplots(1, 3) @@ -66,6 +67,20 @@ target=axs[2], **visual_style, ) -fig.text(0.38, 0.5, '$\simeq$' if g1.isomorphic(g2) else '$\\neq$', fontsize=15, ha='center', va='center') -fig.text(0.65, 0.5, '$\simeq$' if g2.isomorphic(g3) else '$\\neq$', fontsize=15, ha='center', va='center') +fig.text( + 0.38, + 0.5, + "$\\simeq$" if g1.isomorphic(g2) else "$\\neq$", + fontsize=15, + ha="center", + va="center", +) +fig.text( + 0.65, + 0.5, + "$\\simeq$" if g2.isomorphic(g3) else "$\\neq$", + fontsize=15, + ha="center", + va="center", +) plt.show() diff --git a/doc/examples_sphinx-gallery/maxflow.py b/doc/examples_sphinx-gallery/maxflow.py index 246d4c451..eb76684a4 100644 --- a/doc/examples_sphinx-gallery/maxflow.py +++ b/doc/examples_sphinx-gallery/maxflow.py @@ -8,16 +8,13 @@ This example shows how to construct a max flow on a directed graph with edge capacities using :meth:`igraph.Graph.maxflow`. """ + import igraph as ig import matplotlib.pyplot as plt # %% # First, we generate a graph and assign a "capacity" to each edge: -g = ig.Graph( - 6, - [(3, 2), (3, 4), (2, 1), (4,1), (4, 5), (1, 0), (5, 0)], - directed=True -) +g = ig.Graph(6, [(3, 2), (3, 4), (2, 1), (4, 1), (4, 5), (1, 0), (5, 0)], directed=True) g.es["capacity"] = [7, 8, 1, 2, 3, 4, 5] # %% @@ -39,6 +36,6 @@ target=ax, layout="circle", vertex_label=range(g.vcount()), - vertex_color="lightblue" + vertex_color="lightblue", ) plt.show() diff --git a/doc/examples_sphinx-gallery/minimum_spanning_trees.py b/doc/examples_sphinx-gallery/minimum_spanning_trees.py index 50a3d668a..9177e976a 100644 --- a/doc/examples_sphinx-gallery/minimum_spanning_trees.py +++ b/doc/examples_sphinx-gallery/minimum_spanning_trees.py @@ -8,6 +8,7 @@ This example shows how to generate a `minimum spanning tree `_ from an input graph using :meth:`igraph.Graph.spanning_tree`. If you only need a regular spanning tree, check out :ref:`tutorials-spanning-trees`. """ + import random import igraph as ig import matplotlib.pyplot as plt @@ -50,4 +51,3 @@ edge_background="white", ) plt.show() - diff --git a/doc/examples_sphinx-gallery/online_user_actions.py b/doc/examples_sphinx-gallery/online_user_actions.py index 8ad9142d6..47cc00ff5 100644 --- a/doc/examples_sphinx-gallery/online_user_actions.py +++ b/doc/examples_sphinx-gallery/online_user_actions.py @@ -18,23 +18,24 @@ # indicates a certain action taken by a user (e.g. click on a button within a # website). Actual user data usually come with time stamp, but that's not # essential for this example. -action_dataframe = pd.DataFrame([ - ['dsj3239asadsa3', 'createPage', 'greatProject'], - ['2r09ej221sk2k5', 'editPage', 'greatProject'], - ['dsj3239asadsa3', 'editPage', 'greatProject'], - ['789dsadafj32jj', 'editPage', 'greatProject'], - ['oi32ncwosap399', 'editPage', 'greatProject'], - ['4r4320dkqpdokk', 'createPage', 'miniProject'], - ['320eljl3lk3239', 'editPage', 'miniProject'], - ['dsj3239asadsa3', 'editPage', 'miniProject'], - ['3203ejew332323', 'createPage', 'private'], - ['3203ejew332323', 'editPage', 'private'], - ['40m11919332msa', 'createPage', 'private2'], - ['40m11919332msa', 'editPage', 'private2'], - ['dsj3239asadsa3', 'createPage', 'anotherGreatProject'], - ['2r09ej221sk2k5', 'editPage', 'anotherGreatProject'], +action_dataframe = pd.DataFrame( + [ + ["dsj3239asadsa3", "createPage", "greatProject"], + ["2r09ej221sk2k5", "editPage", "greatProject"], + ["dsj3239asadsa3", "editPage", "greatProject"], + ["789dsadafj32jj", "editPage", "greatProject"], + ["oi32ncwosap399", "editPage", "greatProject"], + ["4r4320dkqpdokk", "createPage", "miniProject"], + ["320eljl3lk3239", "editPage", "miniProject"], + ["dsj3239asadsa3", "editPage", "miniProject"], + ["3203ejew332323", "createPage", "private"], + ["3203ejew332323", "editPage", "private"], + ["40m11919332msa", "createPage", "private2"], + ["40m11919332msa", "editPage", "private2"], + ["dsj3239asadsa3", "createPage", "anotherGreatProject"], + ["2r09ej221sk2k5", "editPage", "anotherGreatProject"], ], - columns=['userid', 'action', 'project'], + columns=["userid", "action", "project"], ) # %% @@ -42,7 +43,7 @@ # We choose to use a weighted adjacency matrix for this, i.e. a table with rows # and columns indexes by the users that has nonzero entries whenever folks # collaborate. First, let's get the users and prepare an empty matrix: -users = action_dataframe['userid'].unique() +users = action_dataframe["userid"].unique() adjacency_matrix = pd.DataFrame( np.zeros((len(users), len(users)), np.int32), index=users, @@ -51,8 +52,8 @@ # %% # Then, let's iterate over all projects one by one, and add all collaborations: -for project, project_data in action_dataframe.groupby('project'): - project_users = project_data['userid'].values +for _project, project_data in action_dataframe.groupby("project"): + project_users = project_data["userid"].values for i1, user1 in enumerate(project_users): for user2 in project_users[:i1]: adjacency_matrix.at[user1, user2] += 1 @@ -60,17 +61,17 @@ # %% # There are many ways to achieve the above matrix, so don't be surprised if you # came up with another algorithm ;-) Now it's time to make the graph: -g = ig.Graph.Weighted_Adjacency(adjacency_matrix, mode='plus') +g = ig.Graph.Weighted_Adjacency(adjacency_matrix, mode="plus") # %% # We can take a look at the graph via plotting functions. We can first make a # layout: -layout = g.layout('circle') +layout = g.layout("circle") # %% # Then we can prepare vertex sizes based on their closeness to other vertices vertex_size = g.closeness() -vertex_size = [0.5 * v**2 if not np.isnan(v) else 0.05 for v in vertex_size] +vertex_size = [10 * v**2 if not np.isnan(v) else 10 for v in vertex_size] # %% # Finally, we can plot the graph: @@ -79,7 +80,7 @@ g, target=ax, layout=layout, - vertex_label=g.vs['name'], + vertex_label=g.vs["name"], vertex_color="lightblue", vertex_size=vertex_size, edge_width=g.es["weight"], @@ -89,14 +90,14 @@ # %% # Loops indicate "self-collaborations", which are not very meaningful. To # filter out loops without losing the edge weights, we can use: -g = g.simplify(combine_edges='first') +g = g.simplify(combine_edges="first") fig, ax = plt.subplots() ig.plot( g, target=ax, layout=layout, - vertex_label=g.vs['name'], + vertex_label=g.vs["name"], vertex_color="lightblue", vertex_size=vertex_size, edge_width=g.es["weight"], diff --git a/doc/examples_sphinx-gallery/personalized_pagerank.py b/doc/examples_sphinx-gallery/personalized_pagerank.py new file mode 100644 index 000000000..f7e2f9e2b --- /dev/null +++ b/doc/examples_sphinx-gallery/personalized_pagerank.py @@ -0,0 +1,98 @@ +""" +.. _tutorials-personalized_pagerank: + +=============================== +Personalized PageRank on a grid +=============================== + +This example demonstrates how to calculate and visualize personalized PageRank on a grid. We use the :meth:`igraph.Graph.personalized_pagerank` method, and demonstrate the effects on a grid graph. +""" + +# %% +# .. note:: +# +# The PageRank score of a vertex reflects the probability that a random walker will be at that vertex over the long run. At each step the walker has a 1 - damping chance to restart the walk and pick a starting vertex according to the probabilities defined in the reset vector. + +import igraph as ig +import matplotlib.cm as cm +import matplotlib.pyplot as plt +import numpy as np + +# %% +# We define a function that plots the graph on a Matplotlib axis, along with +# its personalized PageRank values. The function also generates a +# color bar on the side to see how the values change. +# We use `Matplotlib's Normalize class `_ +# to set the colors and ensure that our color bar range is correct. + + +def plot_pagerank(graph: ig.Graph, p_pagerank: list[float]): + """Plots personalized PageRank values on a grid graph with a colorbar. + + Parameters + ---------- + graph : ig.Graph + graph to plot + p_pagerank : list[float] + calculated personalized PageRank values + """ + # Create the axis for matplotlib + _, ax = plt.subplots(figsize=(8, 8)) + + # Create a matplotlib colormap + # coolwarm goes from blue (lowest value) to red (highest value) + cmap = cm.coolwarm + + # Normalize the PageRank values for colormap + normalized_pagerank = ig.rescale(p_pagerank) + + graph.vs["color"] = [cmap(pr) for pr in normalized_pagerank] + graph.vs["size"] = ig.rescale(p_pagerank, (20, 40)) + graph.es["color"] = "gray" + graph.es["width"] = 1.5 + + # Plot the graph + ig.plot(graph, target=ax, layout=graph.layout_grid()) + + # Add a colorbar + sm = cm.ScalarMappable( + norm=plt.Normalize(min(p_pagerank), max(p_pagerank)), cmap=cmap + ) + plt.colorbar(sm, ax=ax, label="Personalized PageRank") + + plt.title("Graph with Personalized PageRank") + plt.axis("equal") + plt.show() + + +# %% +# First, we generate a graph, e.g. a Lattice Graph, which basically is a ``dim x dim`` grid: +dim = 5 +grid_size = (dim, dim) # dim rows, dim columns +g = ig.Graph.Lattice(dim=grid_size, circular=False) + +# %% +# Then we initialize the ``reset_vector`` (it's length should be equal to the number of vertices in the graph): +reset_vector = np.zeros(g.vcount()) + +# %% +# Then we set the nodes to prioritize, for example nodes with indices ``0`` and ``18``: +reset_vector[0] = 1 +reset_vector[18] = 0.65 + +# %% +# Then we calculate the personalized PageRank: +personalized_page_rank = g.personalized_pagerank(damping=0.85, reset=reset_vector) + +# %% +# Finally, we plot the graph with the personalized PageRank values: +plot_pagerank(g, personalized_page_rank) + + +# %% +# Alternatively, we can play around with the ``damping`` parameter: +personalized_page_rank = g.personalized_pagerank(damping=0.45, reset=reset_vector) + +# %% +# Here we can see the same plot with the new damping parameter: +plot_pagerank(g, personalized_page_rank) diff --git a/doc/examples_sphinx-gallery/plot_iplotx.py b/doc/examples_sphinx-gallery/plot_iplotx.py new file mode 100644 index 000000000..5c3c12c43 --- /dev/null +++ b/doc/examples_sphinx-gallery/plot_iplotx.py @@ -0,0 +1,63 @@ +""" +.. _tutorials-iplotx: + +============================== +Visualising graphs with iplotx +============================== +``iplotx`` (https://iplotx.readthedocs.io) is a library for visualisation of graphs/networks +with direct compatibility with both igraph and NetworkX. It uses ``matplotlib`` behind the +scenes so the results are compatible with the current igraph matplotlib backend and many +additional chart types (e.g. bar charts, annotations). + +Compared to the standard visualisations shipped with igraph, ``iplotx`` offers: + +- More styling options +- More consistent behaviour across DPI resolutions and backends +- More consistent matplotlib artists for plot editing and animation + +""" + +import igraph as ig +import iplotx as ipx + +# Construct a graph with 5 vertices +n_vertices = 5 +edges = [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (3, 4)] +g = ig.Graph(n_vertices, edges) + +# Set attributes for the graph, nodes, and edges +g["title"] = "Small Social Network" +g.vs["name"] = [ + "Daniel Morillas", + "Kathy Archer", + "Kyle Ding", + "Joshua Walton", + "Jana Hoyer", +] +g.vs["gender"] = ["M", "F", "F", "M", "F"] +g.es["married"] = [False, False, False, False, False, False, False, True] + +# Set individual attributes +g.vs[1]["name"] = "Kathy Morillas" +g.es[0]["married"] = True + +# Plot using iplotx +ipx.network( + g, + layout="circle", # print nodes in a circular layout + vertex_marker="s", + vertex_size=45, + vertex_linewidth=2, + vertex_facecolor=[ + "lightblue" if gender == "M" else "deeppink" for gender in g.vs["gender"] + ], + vertex_label_color=[ + "black" if gender == "M" else "white" for gender in g.vs["gender"] + ], + vertex_edgecolor="black", + vertex_labels=[name.replace(" ", "\n") for name in g.vs["name"]], + edge_linewidth=[2 if married else 1 for married in g.es["married"]], + edge_color=["#7142cf" if married else "#AAA" for married in g.es["married"]], + edge_padding=3, + aspect=1.0, +) diff --git a/doc/examples_sphinx-gallery/quickstart.py b/doc/examples_sphinx-gallery/quickstart.py index 8edf0c9d3..0735768e5 100644 --- a/doc/examples_sphinx-gallery/quickstart.py +++ b/doc/examples_sphinx-gallery/quickstart.py @@ -15,17 +15,24 @@ To find out more features that igraph has to offer, check out the :ref:`gallery`! """ + import igraph as ig import matplotlib.pyplot as plt -# Construct a graph with 3 vertices -n_vertices = 3 +# Construct a graph with 5 vertices +n_vertices = 5 edges = [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (3, 4)] g = ig.Graph(n_vertices, edges) # Set attributes for the graph, nodes, and edges g["title"] = "Small Social Network" -g.vs["name"] = ["Daniel Morillas", "Kathy Archer", "Kyle Ding", "Joshua Walton", "Jana Hoyer"] +g.vs["name"] = [ + "Daniel Morillas", + "Kathy Archer", + "Kyle Ding", + "Joshua Walton", + "Jana Hoyer", +] g.vs["gender"] = ["M", "F", "F", "M", "F"] g.es["married"] = [False, False, False, False, False, False, False, True] @@ -35,27 +42,29 @@ # Plot in matplotlib # Note that attributes can be set globally (e.g. vertex_size), or set individually using arrays (e.g. vertex_color) -fig, ax = plt.subplots(figsize=(5,5)) +fig, ax = plt.subplots(figsize=(5, 5)) ig.plot( g, target=ax, - layout="circle", # print nodes in a circular layout - vertex_size=0.1, - vertex_color=["steelblue" if gender == "M" else "salmon" for gender in g.vs["gender"]], + layout="circle", # print nodes in a circular layout + vertex_size=30, + vertex_color=[ + "steelblue" if gender == "M" else "salmon" for gender in g.vs["gender"] + ], vertex_frame_width=4.0, vertex_frame_color="white", vertex_label=g.vs["name"], vertex_label_size=7.0, edge_width=[2 if married else 1 for married in g.es["married"]], - edge_color=["#7142cf" if married else "#AAA" for married in g.es["married"]] + edge_color=["#7142cf" if married else "#AAA" for married in g.es["married"]], ) plt.show() # Save the graph as an image file -fig.savefig('social_network.png') -fig.savefig('social_network.jpg') -fig.savefig('social_network.pdf') +fig.savefig("social_network.png") +fig.savefig("social_network.jpg") +fig.savefig("social_network.pdf") # Export and import a graph as a GML file. g.save("social_network.gml") diff --git a/doc/examples_sphinx-gallery/ring_animation.py b/doc/examples_sphinx-gallery/ring_animation.py index 25daa2918..33bd6a109 100644 --- a/doc/examples_sphinx-gallery/ring_animation.py +++ b/doc/examples_sphinx-gallery/ring_animation.py @@ -9,6 +9,7 @@ order to animate a ring graph sequentially being revealed. """ + import igraph as ig import matplotlib.pyplot as plt import matplotlib.animation as animation @@ -23,6 +24,7 @@ # Compute a 2D ring layout that looks like an actual ring layout = g.layout_circle() + # %% # Prepare an update function. This "callback" function will be run at every # frame and takes as a single argument the frame number. For simplicity, at @@ -71,6 +73,7 @@ def _update_graph(frame): handles = ax.get_children()[:nhandles] return handles + # %% # Run the animation fig, ax = plt.subplots() diff --git a/doc/examples_sphinx-gallery/shortest_path_visualisation.py b/doc/examples_sphinx-gallery/shortest_path_visualisation.py index de17c0d0d..fedad160a 100644 --- a/doc/examples_sphinx-gallery/shortest_path_visualisation.py +++ b/doc/examples_sphinx-gallery/shortest_path_visualisation.py @@ -8,15 +8,13 @@ This example demonstrates how to find the shortest distance between two vertices of a weighted or an unweighted graph. """ + import igraph as ig import matplotlib.pyplot as plt # %% # To find the shortest path or distance between two nodes, we can use :meth:`igraph.GraphBase.get_shortest_paths`. If we're only interested in counting the unweighted distance, then we can do the following: -g = ig.Graph( - 6, - [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)] -) +g = ig.Graph(6, [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5)]) results = g.get_shortest_paths(1, to=4, output="vpath") # results = [[1, 0, 2, 4]] @@ -25,7 +23,7 @@ # We can print the result of the computation: if len(results[0]) > 0: # The distance is the number of vertices in the shortest path minus one. - print("Shortest distance is: ", len(results[0])-1) + print("Shortest distance is: ", len(results[0]) - 1) else: print("End node could not be reached!") @@ -54,26 +52,26 @@ # %% # .. note:: -# +# # - :meth:`igraph.GraphBase.get_shortest_paths` returns a list of lists becuase the `to` argument can also accept a list of vertex IDs. In that case, the shortest path to all each vertex is found and stored in the results array. # - If you're interested in finding *all* shortest paths, take a look at :meth:`igraph.GraphBase.get_all_shortest_paths`. # %% # In case you are wondering how the visualization figure was done, here's the code: -g.es['width'] = 0.5 -g.es[results[0]]['width'] = 2.5 +g.es["width"] = 0.5 +g.es[results[0]]["width"] = 2.5 fig, ax = plt.subplots() ig.plot( g, target=ax, - layout='circle', - vertex_color='steelblue', + layout="circle", + vertex_color="steelblue", vertex_label=range(g.vcount()), - edge_width=g.es['width'], + edge_width=g.es["width"], edge_label=g.es["weight"], - edge_color='#666', + edge_color="#666", edge_align_label=True, - edge_background='white' + edge_background="white", ) plt.show() diff --git a/doc/examples_sphinx-gallery/simplify.py b/doc/examples_sphinx-gallery/simplify.py index 6d626fc71..ed36b2da5 100644 --- a/doc/examples_sphinx-gallery/simplify.py +++ b/doc/examples_sphinx-gallery/simplify.py @@ -5,25 +5,28 @@ This example shows how to remove self loops and multiple edges using :meth:`igraph.GraphBase.simplify`. """ + import igraph as ig import matplotlib.pyplot as plt # %% # We start with a graph that includes loops and multiedges: -g1 = ig.Graph([ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (4, 0), - (0, 0), - (1, 4), - (1, 4), - (0, 2), - (2, 4), - (2, 4), - (2, 4), - (3, 3)], +g1 = ig.Graph( + [ + (0, 1), + (1, 2), + (2, 3), + (3, 4), + (4, 0), + (0, 0), + (1, 4), + (1, 4), + (0, 2), + (2, 4), + (2, 4), + (2, 4), + (3, 3), + ], ) # %% @@ -39,7 +42,7 @@ # choose a consistent visual style: visual_style = { "vertex_color": "lightblue", - "vertex_size": 0.4, + "vertex_size": 20, "vertex_label": [0, 1, 2, 3, 4], } @@ -59,13 +62,29 @@ target=axs[1], **visual_style, ) -axs[0].set_title('Multigraph...') -axs[1].set_title('...simplified') +axs[0].set_title("Multigraph...") +axs[1].set_title("...simplified") # Draw rectangles around axes -axs[0].add_patch(plt.Rectangle( - (0, 0), 1, 1, fc='none', ec='k', lw=4, transform=axs[0].transAxes, - )) -axs[1].add_patch(plt.Rectangle( - (0, 0), 1, 1, fc='none', ec='k', lw=4, transform=axs[1].transAxes, - )) +axs[0].add_patch( + plt.Rectangle( + (0, 0), + 1, + 1, + fc="none", + ec="k", + lw=4, + transform=axs[0].transAxes, + ) +) +axs[1].add_patch( + plt.Rectangle( + (0, 0), + 1, + 1, + fc="none", + ec="k", + lw=4, + transform=axs[1].transAxes, + ) +) plt.show() diff --git a/doc/examples_sphinx-gallery/spanning_trees.py b/doc/examples_sphinx-gallery/spanning_trees.py index e9b083f60..be98501af 100644 --- a/doc/examples_sphinx-gallery/spanning_trees.py +++ b/doc/examples_sphinx-gallery/spanning_trees.py @@ -7,6 +7,7 @@ This example shows how to generate a spanning tree from an input graph using :meth:`igraph.Graph.spanning_tree`. For the related idea of finding a *minimum spanning tree*, see :ref:`tutorials-minimum-spanning-trees`. """ + import igraph as ig import matplotlib.pyplot as plt import random @@ -29,7 +30,7 @@ g = g.permute_vertices(permutation) new_layout = g.layout("grid") for i in range(36): - new_layout[permutation[i]] = layout[i] + new_layout[i] = layout[permutation[i]] layout = new_layout # %% @@ -47,11 +48,10 @@ g.es[spanning_tree]["width"] = 3.0 fig, ax = plt.subplots() -ig.plot( - g, - target=ax, - layout=layout, - vertex_color="lightblue", - edge_width=g.es["width"] -) +ig.plot(g, target=ax, layout=layout, vertex_color="lightblue", edge_width=g.es["width"]) plt.show() + +# %% +# .. note:: +# To invert the y axis such that the root of the tree is on top of the plot, +# you can call `ax.invert_yaxis()` before `plt.show()`. diff --git a/doc/examples_sphinx-gallery/stochastic_variability.py b/doc/examples_sphinx-gallery/stochastic_variability.py new file mode 100644 index 000000000..2afc01153 --- /dev/null +++ b/doc/examples_sphinx-gallery/stochastic_variability.py @@ -0,0 +1,171 @@ +""" +.. _tutorials-stochastic-variability: + +========================================================= +Stochastic Variability in Community Detection Algorithms +========================================================= + +This example demonstrates the use of stochastic community detection methods to check whether a network possesses a strong community structure, and whether the partitionings we obtain are meaningul. Many community detection algorithms are randomized, and return somewhat different results after each run, depending on the random seed that was set. When there is a robust community structure, we expect these results to be similar to each other. When the community structure is weak or non-existent, the results may be noisy and highly variable. We will employ several partion similarity measures to analyse the consistency of the results, including the normalized mutual information (NMI), the variation of information (VI), and the Rand index (RI). + +""" + +# %% +import igraph as ig +import matplotlib.pyplot as plt +import itertools +import random + +# %% +# .. note:: +# We set a random seed to ensure that the results look exactly the same in +# the gallery. You don't need to do this when exploring randomness. +random.seed(42) + +# %% +# We will use Zachary's karate club dataset [1]_, a classic example of a network +# with a strong community structure: +karate = ig.Graph.Famous("Zachary") + +# %% +# We will compare it to an an Erdős-Rényi :math:`G(n, m)` random network having +# the same number of vertices and edges. The parameters 'n' and 'm' refer to the +# vertex and edge count, respectively. Since this is a random network, it should +# have no community structure. +random_graph = ig.Graph.Erdos_Renyi(n=karate.vcount(), m=karate.ecount()) + +# %% +# First, let us plot the two networks for a visual comparison: + +# Create subplots +fig, axes = plt.subplots(1, 2, figsize=(12, 6), subplot_kw={"aspect": "equal"}) + +# Karate club network +ig.plot( + karate, + target=axes[0], + vertex_color="lightblue", + vertex_size=30, + vertex_label=range(karate.vcount()), + vertex_label_size=10, + edge_width=1, +) +axes[0].set_title("Karate club network") + +# Random network +ig.plot( + random_graph, + target=axes[1], + vertex_color="lightcoral", + vertex_size=30, + vertex_label=range(random_graph.vcount()), + vertex_label_size=10, + edge_width=1, +) +axes[1].set_title("Erdős-Rényi random network") + +plt.show() + + +# %% +# Function to compute similarity between partitions using various methods: +def compute_pairwise_similarity(partitions, method): + similarities = [] + + for p1, p2 in itertools.combinations(partitions, 2): + similarity = ig.compare_communities(p1, p2, method=method) + similarities.append(similarity) + + return similarities + + +# %% +# The Leiden method, accessible through :meth:`igraph.Graph.community_leiden()`, +# is a modularity maximization approach for community detection. Since exact +# modularity maximization is NP-hard, the algorithm employs a greedy heuristic +# that processes vertices in a random order. This randomness leads to +# variation in the detected communities across different runs, which is why +# results may differ each time the method is applied. The following function +# runs the Leiden algorithm multiple times: +def run_experiment(graph, iterations=100): + partitions = [ + graph.community_leiden(objective_function="modularity").membership + for _ in range(iterations) + ] + nmi_scores = compute_pairwise_similarity(partitions, method="nmi") + vi_scores = compute_pairwise_similarity(partitions, method="vi") + ri_scores = compute_pairwise_similarity(partitions, method="rand") + return nmi_scores, vi_scores, ri_scores + + +# %% +# Run the experiment on both networks: +nmi_karate, vi_karate, ri_karate = run_experiment(karate) +nmi_random, vi_random, ri_random = run_experiment(random_graph) + +# %% +# Finally, let us plot histograms of the pairwise similarities of the obtained +# partitionings to understand the result: +fig, axes = plt.subplots(2, 3, figsize=(12, 6)) +measures = [ + # Normalized Mutual Information (0-1, higher = more similar) + (nmi_karate, nmi_random, "NMI", 0, 1), + # Variation of Information (0+, lower = more similar) + (vi_karate, vi_random, "VI", 0, max(vi_karate + vi_random)), + # Rand Index (0-1, higher = more similar) + (ri_karate, ri_random, "RI", 0, 1), +] +colors = ["red", "blue", "green"] + +for i, (karate_scores, random_scores, measure, lower, upper) in enumerate(measures): + # Karate club histogram + axes[0][i].hist( + karate_scores, + bins=20, + range=(lower, upper), + density=True, # Probability density + alpha=0.7, + color=colors[i], + edgecolor="black", + ) + axes[0][i].set_title(f"{measure} - Karate club network") + axes[0][i].set_xlabel(f"{measure} score") + axes[0][i].set_ylabel("PDF") + + # Random network histogram + axes[1][i].hist( + random_scores, + bins=20, + range=(lower, upper), + density=True, + alpha=0.7, + color=colors[i], + edgecolor="black", + ) + axes[1][i].set_title(f"{measure} - Random network") + axes[1][i].set_xlabel(f"{measure} score") + axes[0][i].set_ylabel("PDF") + +plt.tight_layout() +plt.show() + +# %% +# We have compared the pairwise similarities using the NMI, VI, and RI measures +# between partitonings obtained for the karate club network (strong community +# structure) and a comparable random graph (which lacks communities). +# +# The Normalized Mutual Information (NMI) and Rand Index (RI) both quantify +# similarity, and take values from :math:`[0,1]`. Higher values indicate more +# similar partitionings, with a value of 1 attained when the partitionings are +# identical. +# +# The Variation of Information (VI) is a distance measure. It takes values from +# :math:`[0,\infty]`, with lower values indicating higher similarities. Identical +# partitionings have a distance of zero. +# +# For the karate club network, NMI and RI value are concentrated near 1, while +# VI is concentrated near 0, suggesting a robust community structure. In contrast +# the values obtained for the random network are much more spread out, showing +# inconsistent partitionings due to the lack of a clear community structure. + +# %% +# .. [1] W. Zachary: "An Information Flow Model for Conflict and Fission in Small Groups". Journal of Anthropological Research 33, no. 4 (1977): 452–73. https://www.jstor.org/stable/3629752 diff --git a/doc/examples_sphinx-gallery/topological_sort.py b/doc/examples_sphinx-gallery/topological_sort.py index 04971131b..3c558f90b 100644 --- a/doc/examples_sphinx-gallery/topological_sort.py +++ b/doc/examples_sphinx-gallery/topological_sort.py @@ -7,6 +7,7 @@ This example demonstrates how to get a topological sorting on a directed acyclic graph (DAG). A topological sorting of a directed graph is a linear ordering based on the precedence implied by the directed edges. It exists iff the graph doesn't have any cycle. In ``igraph``, we can use :meth:`igraph.GraphBase.topological_sorting` to get a topological ordering of the vertices. """ + import igraph as ig import matplotlib.pyplot as plt @@ -21,26 +22,26 @@ # %% # We can verify immediately that this is actually a DAG: assert g.is_dag - + # %% # A topological sorting can be computed quite easily by calling # :meth:`igraph.GraphBase.topological_sorting`, which returns a list of vertex IDs. # If the given graph is not DAG, the error will occur. -results = g.topological_sorting(mode='out') -print('Topological sort of g (out):', *results) +results = g.topological_sorting(mode="out") +print("Topological sort of g (out):", *results) # %% # In fact, there are two modes of :meth:`igraph.GraphBase.topological_sorting`, # ``'out'`` ``'in'``. ``'out'`` is the default and starts from a node with # indegree equal to 0. Vice versa, ``'in'`` starts from a node with outdegree # equal to 0. To call the other mode, we can simply use: -results = g.topological_sorting(mode='in') -print('Topological sort of g (in):', *results) +results = g.topological_sorting(mode="in") +print("Topological sort of g (in):", *results) # %% # We can use :meth:`igraph.Vertex.indegree` to find the indegree of the node. for i in range(g.vcount()): - print('degree of {}: {}'.format(i, g.vs[i].indegree())) + print("degree of {}: {}".format(i, g.vs[i].indegree())) # % # Finally, we can plot the graph to make the situation a little clearer. @@ -49,11 +50,11 @@ with plt.xkcd(): fig, ax = plt.subplots(figsize=(5, 5)) ig.plot( - g, - target=ax, - layout='kk', - vertex_size=0.3, - edge_width=4, - vertex_label=range(g.vcount()), - vertex_color="white", - ) + g, + target=ax, + layout="kk", + vertex_size=25, + edge_width=4, + vertex_label=range(g.vcount()), + vertex_color="white", + ) diff --git a/doc/examples_sphinx-gallery/visual_style.py b/doc/examples_sphinx-gallery/visual_style.py index 8273edfd6..30c27d73b 100644 --- a/doc/examples_sphinx-gallery/visual_style.py +++ b/doc/examples_sphinx-gallery/visual_style.py @@ -6,6 +6,7 @@ This example shows how to change the visual style of network plots. """ + import igraph as ig import matplotlib.pyplot as plt import random @@ -15,9 +16,9 @@ # various setting we want to customize: visual_style = { "edge_width": 0.3, - "vertex_size": 1.5, + "vertex_size": 15, "palette": "heat", - "layout": "fruchterman_reingold" + "layout": "fruchterman_reingold", } # %% @@ -47,3 +48,44 @@ # default, you can use igraph's `configuration instance # :class:`igraph.configuration.Configuration`. A quick example on how to use # it can be found here: :ref:`tutorials-configuration`. + +# %% +# In the matplotlib backend, igraph creates a special container +# :class:`igraph.drawing.matplotlib.graph.GraphArtist` which is a matplotlib Artist +# and the first child of the target Axes. That object can be used to customize +# the plot appearance after the initial drawing, e.g.: +g = ig.Graph.Barabasi(n=30, m=1) +fig, ax = plt.subplots() +ig.plot(g, target=ax) +artist = ax.get_children()[0] +# Option 1: +artist.set(vertex_color="blue") +# Option 2: +artist.set_vertex_color("blue") +plt.show() + +# %% +# .. note:: +# The :meth:`igraph.drawing.matplotlib.graph.GraphArtist.set` method can +# be used to change multiple properties at once and is generally more +# efficient than multiple calls to specific ``artist.set_...`` methods. + +# %% +# In the matplotlib backend, you can also specify the size of self-loops, +# either as a number or a sequence of numbers, e.g.: +g = ig.Graph(n=5) +g.add_edge(2, 3) +g.add_edge(0, 0) +g.add_edge(1, 1) +fig, ax = plt.subplots() +ig.plot( + g, + target=ax, + vertex_size=20, + edge_loop_size=[ + 0, # ignored, the first edge is not a loop + 30, # loop for vertex 0 + 80, # loop for vertex 1 + ], +) +plt.show() diff --git a/doc/examples_sphinx-gallery/visualize_cliques.py b/doc/examples_sphinx-gallery/visualize_cliques.py index 44f0ff713..c1ebd49d6 100644 --- a/doc/examples_sphinx-gallery/visualize_cliques.py +++ b/doc/examples_sphinx-gallery/visualize_cliques.py @@ -8,12 +8,13 @@ This example shows how to compute and visualize cliques of a graph using :meth:`igraph.GraphBase.cliques`. """ + import igraph as ig import matplotlib.pyplot as plt # %% # First, let's create a graph, for instance the famous karate club graph: -g = ig.Graph.Famous('Zachary') +g = ig.Graph.Famous("Zachary") # %% # Computing cliques can be done as follows: @@ -27,11 +28,13 @@ for clique, ax in zip(cliques, axs): ig.plot( ig.VertexCover(g, [clique]), - mark_groups=True, palette=ig.RainbowPalette(), + mark_groups=True, + palette=ig.RainbowPalette(), + vertex_size=5, edge_width=0.5, target=ax, ) -plt.axis('off') +plt.axis("off") plt.show() @@ -44,23 +47,23 @@ axs = axs.ravel() for clique, ax in zip(cliques, axs): # Color vertices yellow/red based on whether they are in this clique - g.vs['color'] = 'yellow' - g.vs[clique]['color'] = 'red' + g.vs["color"] = "yellow" + g.vs[clique]["color"] = "red" # Color edges black/red based on whether they are in this clique clique_edges = g.es.select(_within=clique) - g.es['color'] = 'black' - clique_edges['color'] = 'red' + g.es["color"] = "black" + clique_edges["color"] = "red" # also increase thickness of clique edges - g.es['width'] = 0.3 - clique_edges['width'] = 1 + g.es["width"] = 0.3 + clique_edges["width"] = 1 ig.plot( ig.VertexCover(g, [clique]), mark_groups=True, palette=ig.RainbowPalette(), + vertex_size=5, target=ax, ) -plt.axis('off') +plt.axis("off") plt.show() - diff --git a/doc/examples_sphinx-gallery/visualize_communities.py b/doc/examples_sphinx-gallery/visualize_communities.py index 7cfd90746..9ab696e8e 100644 --- a/doc/examples_sphinx-gallery/visualize_communities.py +++ b/doc/examples_sphinx-gallery/visualize_communities.py @@ -7,6 +7,7 @@ This example shows how to visualize communities or clusters of a graph. """ + import igraph as ig import matplotlib.pyplot as plt @@ -33,21 +34,22 @@ # %% # Last, we plot the graph. We use a fancy technique called proxy artists to # make a legend. You can find more about that in matplotlib's -# :doc:`matplotlib:tutorials/intermediate/legend_guide`: +# :doc:`matplotlib:users/explain/axes/legend_guide`: fig, ax = plt.subplots() ig.plot( communities, palette=palette, edge_width=1, target=ax, - vertex_size=0.3, + vertex_size=20, ) # Create a custom color legend legend_handles = [] for i in range(num_communities): handle = ax.scatter( - [], [], + [], + [], s=100, facecolor=palette.get(i), edgecolor="k", @@ -56,7 +58,7 @@ legend_handles.append(handle) ax.legend( handles=legend_handles, - title='Community:', + title="Community:", bbox_to_anchor=(0, 1.0), bbox_transform=ax.transAxes, ) diff --git a/doc/jekyll_tools/Gemfile b/doc/jekyll_tools/Gemfile deleted file mode 100644 index 3e5e9cbd3..000000000 --- a/doc/jekyll_tools/Gemfile +++ /dev/null @@ -1,5 +0,0 @@ -source 'http://rubygems.org' - -gem 'jekyll-sitemap' -gem "webrick", "~> 1.7" -gem 'jekyll-redirect-from' diff --git a/doc/jekyll_tools/Gemfile.lock b/doc/jekyll_tools/Gemfile.lock deleted file mode 100644 index 710e3df51..000000000 --- a/doc/jekyll_tools/Gemfile.lock +++ /dev/null @@ -1,74 +0,0 @@ -GEM - remote: http://rubygems.org/ - specs: - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - colorator (1.1.0) - concurrent-ruby (1.1.9) - em-websocket (0.5.3) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0) - eventmachine (1.2.7) - ffi (1.15.4) - forwardable-extended (2.6.0) - http_parser.rb (0.8.0) - i18n (1.8.11) - concurrent-ruby (~> 1.0) - jekyll (4.2.1) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (~> 2.0) - jekyll-watch (~> 2.0) - kramdown (~> 2.3) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (~> 0.4.0) - pathutil (~> 0.9) - rouge (~> 3.0) - safe_yaml (~> 1.0) - terminal-table (~> 2.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-sass-converter (2.1.0) - sassc (> 2.0.1, < 3.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - kramdown (2.3.1) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.3) - listen (3.7.0) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.4.0) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (4.0.6) - rb-fsevent (0.11.0) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.5) - rouge (3.27.0) - safe_yaml (1.0.5) - sassc (2.4.0) - ffi (~> 1.9) - terminal-table (2.0.0) - unicode-display_width (~> 1.1, >= 1.1.1) - unicode-display_width (1.8.0) - webrick (1.7.0) - -PLATFORMS - x86_64-linux - -DEPENDENCIES - jekyll-redirect-from - jekyll-sitemap - webrick (~> 1.7) - -BUNDLED WITH - 2.2.26 diff --git a/doc/jekyll_tools/Makefile b/doc/jekyll_tools/Makefile deleted file mode 100644 index aa1a6dbf8..000000000 --- a/doc/jekyll_tools/Makefile +++ /dev/null @@ -1,130 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/igraph.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/igraph.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/igraph" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/igraph" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - make -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/jekyll_tools/_config.yml b/doc/jekyll_tools/_config.yml deleted file mode 100644 index b9a8a09d7..000000000 --- a/doc/jekyll_tools/_config.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: igraph – the network analysis package -destination: jekyll_output -future: true -include: [ _static, _images ] -exclude: [ source, Gemfile, Gemfile.lock, build_old_sources.py ] -keep_files: [ ] -markdown: kramdown -kramdown: - input: GFM -url: "https://igraph.org/python" -plugins: - - jekyll-sitemap -defaults: - - - scope: - path: "" - values: - layout: "post" diff --git a/doc/jekyll_tools/_includes/defaults b/doc/jekyll_tools/_includes/defaults deleted file mode 100644 index 42baf8c90..000000000 --- a/doc/jekyll_tools/_includes/defaults +++ /dev/null @@ -1,16 +0,0 @@ -{% assign lang = "python" %} -{%- assign bodyclass = lang %} -{% assign title = page.title %} -{% assign mainheader = page.mainheader %} -{% assign lead = page.lead %} - -{% assign langname = 'python-igraph' %} -{% assign langversions = version | split: ", " %} -{% if title == nil %}{% assign title = 'python-igraph' %}{% endif %} -{% assign extramenu = '
  • Get started
  • ' %} -{% if mainheader == nil %} - {% assign mainheader = 'Get started with python-igraph' %} -{% endif %} -{% if lead == nil %} - {% assign lead = 'Install and start using igraph from Python' %} -{% endif %} diff --git a/doc/jekyll_tools/_layouts/default.html b/doc/jekyll_tools/_layouts/default.html deleted file mode 100644 index d74c2b8b1..000000000 --- a/doc/jekyll_tools/_layouts/default.html +++ /dev/null @@ -1,156 +0,0 @@ -{% include defaults %} - - - - - - - - - - - - - - {{ title }} - - - - - - - - - - - - - - - - - - - - {{ page.extrahead | default: layout.extrahead }} - - - -
    - - - {% if page.layout != "main" %} - -
    -
    -

    {{ page.mainheader | default: layout.mainheader }}

    -

    {{ page.lead | default: layout.lead }}

    -
    - -
    - - {% endif %} - - {{content}} - - - - -
    - - - - - - - - - -{% if page.animated_header or layout.animated_header %} - - -{% endif %} - - diff --git a/doc/jekyll_tools/_layouts/main.html b/doc/jekyll_tools/_layouts/main.html deleted file mode 100644 index 42c90e4f6..000000000 --- a/doc/jekyll_tools/_layouts/main.html +++ /dev/null @@ -1,75 +0,0 @@ ---- -layout: default -bodyclass: start-page -animated_header: true ---- - -
    -
    -

    igraph – - The network analysis package -

    -

    - igraph is a collection of network analysis tools with the - emphasis on efficiency, - portability and ease of use. igraph is - open source and free. igraph can be - programmed in R, Python, - Mathematica and C/C++. -

    -
    - igraph R package - python-igraph - IGraph/M - igraph C library -
    - -
    - -
    -
    -
    - -
    - -
    -
    - - - - {% for post in site.posts limit:10 %} - -
    -

    -   - {{ post.title }} -

    -
    -
    - - {{ post.content | extract_excerpt: post.url | redir_docs | smallheaders }} - -
    - - {% endfor %} - -

    All news →

    - -
    -
    -
    - -
    diff --git a/doc/jekyll_tools/_layouts/pydoctor.html b/doc/jekyll_tools/_layouts/pydoctor.html deleted file mode 100644 index e70459159..000000000 --- a/doc/jekyll_tools/_layouts/pydoctor.html +++ /dev/null @@ -1,18 +0,0 @@ ---- -layout: default -extrahead: -vmenu: true -doctype: api/ ---- - -
    -
    -
    -
    - - {{ content }} - -
    -
    -
    -
    diff --git a/doc/jekyll_tools/css/affix.css b/doc/jekyll_tools/css/affix.css deleted file mode 100644 index 5b57395ef..000000000 --- a/doc/jekyll_tools/css/affix.css +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Side navigation - * - * Scrollspy and affixed enhanced navigation to highlight sections and secondary - * sections of docs content. - */ - -/* By default it's not affixed in mobile views, so undo that */ -.bs-sidebar.affix { - position: static; -} - -/* First level of nav */ -.bs-sidenav { - margin-top: 30px; - margin-bottom: 30px; - padding-top: 10px; - padding-bottom: 10px; - text-shadow: 0 1px 0 #fff; - background-color: #e9ecef; - border-radius: 5px; -} - -/* All levels of nav */ -.bs-sidebar .nav > li { - width: 100%; -} - -.bs-sidebar .nav > li > a { - display: block; - color: #716b7a; - padding: 5px 20px; -} -.bs-sidebar .nav > li > a:hover, -.bs-sidebar .nav > li > a:focus { - text-decoration: none; - background-color: #d3d9df; - border-right: 2px solid #a7b3bf; -} -.bs-sidebar .nav > li > a.active, -.bs-sidebar .nav > li > a.active:hover, -.bs-sidebar .nav > li > a.active:focus { - font-weight: bold; - color: #563d7c; - background-color: transparent; - border-right: 2px solid #563d7c; -} - -/* Nav: second level (shown on .active) */ -.bs-sidebar .nav .nav { - display: none; /* Hide by default, but at >768px, show it */ - margin-bottom: 8px; -} -.bs-sidebar .nav .nav > li > a { - padding-top: 3px; - padding-bottom: 3px; - padding-left: 30px; - font-size: 90%; -} - -/* Show and affix the side nav when space allows it */ -@media (min-width: 992px) { - .bs-sidebar .nav .nav-item > a.active + ul { - display: block; - } - /* Widen the fixed sidebar */ - .bs-sidebar.affix, - .bs-sidebar.affix-bottom { - width: 213px; - } - .bs-sidebar.affix { - position: sticky; /* Undo the static from mobile first approach */ - top: 80px; - } - .bs-sidebar.affix-bottom { - position: absolute; /* Undo the static from mobile first approach */ - } - .bs-sidebar.affix-bottom .bs-sidenav, - .bs-sidebar.affix .bs-sidenav { - margin-top: 0; - margin-bottom: 0; - } -} -@media (min-width: 1200px) { - /* Widen the fixed sidebar again */ - .bs-sidebar.affix-bottom, - .bs-sidebar.affix { - width: 263px; - } -} diff --git a/doc/jekyll_tools/css/bootstrap.min.css b/doc/jekyll_tools/css/bootstrap.min.css deleted file mode 100644 index ad8c117b8..000000000 --- a/doc/jekyll_tools/css/bootstrap.min.css +++ /dev/null @@ -1 +0,0 @@ -: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:#dc3545;--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;text-decoration:underline dotted;cursor:help;border-bottom:0;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:#dc3545;text-decoration:none;background-color:transparent}a:hover{color:#a71d2a;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:flex;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{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;width:auto;max-width:100%}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;width:auto;max-width:100%}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.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:#f5c6cb}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#ed969e}.table-hover .table-primary:hover{background-color:#f1b0b7}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#f1b0b7}.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:#efa2a9;outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.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:flex;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:inline-flex;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:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;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:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items: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;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(220,53,69,.25)}.btn.disabled,.btn:disabled{opacity:.65}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-primary:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.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(225,83,97,.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:#dc3545;border-color:#dc3545}.btn-outline-primary:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#dc3545;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:#dc3545;border-color:#dc3545}.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(220,53,69,.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:#dc3545;text-decoration:none}.btn-link:hover{color:#a71d2a;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:#dc3545}.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:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;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:flex;flex-wrap:wrap;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{flex-direction:column;align-items:flex-start;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:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;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:flex;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: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:flex;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: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:#dc3545;background-color:#dc3545}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#efa2a9}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#f6cdd1;border-color:#f6cdd1}.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:#dc3545;background-color:#dc3545}.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(220,53,69,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(220,53,69,.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(220,53,69,.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:transform .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){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(220,53,69,.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;appearance:none}.custom-select:focus{border-color:#efa2a9;outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.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:#efa2a9;box-shadow:0 0 0 .2rem rgba(220,53,69,.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;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(220,53,69,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#dc3545;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::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#f6cdd1}.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:#dc3545;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::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#f6cdd1}.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:#dc3545;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:#f6cdd1}.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:flex;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:#dc3545}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:flex;flex-wrap:wrap;align-items:center;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:flex;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{flex-basis:100%;flex-grow:1;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{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{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{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;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{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{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{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;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{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{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{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;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{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{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{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{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{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;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:flex;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{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:flex;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:flex;flex:1 0 0%;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:flex;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{flex-flow:row wrap}.card-group>.card{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{column-count:3;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:flex;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: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:#dc3545;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#a71d2a;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.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:#dc3545;border-color:#dc3545}.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:#dc3545}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#bd2130}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.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:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-primary hr{border-top-color:#f1b0b7}.alert-primary .alert-link{color:#491217}.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}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#dc3545;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{animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;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:#dc3545;border-color:#dc3545}.list-group-horizontal{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{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{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{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{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:#721c24;background-color:#f5c6cb}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.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;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);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:flex;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:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal-dialog-scrollable{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{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;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{flex-direction:column;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:flex;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:flex;align-items:flex-start;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;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;align-items:center;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{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%;backface-visibility:hidden;transition: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){transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;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:flex;align-items: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:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;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}@keyframes spinner-border{to{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%;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{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;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:#dc3545!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#bd2130!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:#dc3545!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:flex!important}.d-inline-flex{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:flex!important}.d-sm-inline-flex{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:flex!important}.d-md-inline-flex{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:flex!important}.d-lg-inline-flex{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:flex!important}.d-xl-inline-flex{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:flex!important}.d-print-inline-flex{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.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{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: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:sticky){.sticky-top{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:#dc3545!important}a.text-primary:focus,a.text-primary:hover{color:#a71d2a!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}} \ No newline at end of file diff --git a/doc/jekyll_tools/css/other.css b/doc/jekyll_tools/css/other.css deleted file mode 100644 index ca975001e..000000000 --- a/doc/jekyll_tools/css/other.css +++ /dev/null @@ -1,205 +0,0 @@ -/* Sticky footer, http://getbootstrap.com/examples/sticky-footer-navbar/ */ - -html { - min-height: 100%; - scroll-padding-top: 80px; -} - -html, -body { - height: 100%; - background-color: #fff; -} - -body { - position: relative; -} - -nav.fixed-top { - box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); -} - -span.type { - font-family: monospace; - font-size: 87.5%; -} - -#wrap { - min-height: 100%; - position: relative; - /* Pad top by header height, bottom by footer */ - padding: 57px 0 0 0; -} - -#footer { - width: 100%; -} - -#footer .credit { - text-align: center; -} - -/* -.navbar-brand -{ - padding-right: 5px; -} - -.navbar-brand img -{ - margin-right: 5px; -} -*/ - -.gist { - line-height: 1.2; -} - -@media(min-width:768px) { - .bs-docs-section { - font-size: 140%; - } - .bs-sidebar { - font-size: 120%; - } - .gist .gist-file .gist-data { - font-size: 80% !important; - } -} - -.bs-docs-section .navigation-header { - margin-bottom: 1.5rem; -} -.bs-docs-section h1 { - margin: 2.5rem 0; -} -.bs-docs-section h2 { - margin: 2.5rem 0 1.5rem 0; -} -.bs-docs-section h3 { - margin: 2.5rem 0 1.5rem 0; -} - -.bs-docs-section .page-header:first-child h1, -.bs-docs-section .post-header:first-child h1 -{ - margin-top: 0 !important; -} - -.post-header h1, -.post-header h2 { - margin-bottom: 0.5rem !important; -} -.post-header .post-time { - margin-bottom: 1.5rem; -} - -code { - color: #87556e; -} - -code.rfun:after { - content: "()"; -} - -/* Page headers */ -.bs-header { - padding: 20px 15px 20px; /* side padding builds on .container 15px, so 30px */ - font-size: 16px; - text-align: center; - text-shadow: 0 1px 0 rgba(0,0,0,.15); - color: white; - margin-bottom: 30px; - background: #3e648d; - background-image: -webkit-gradient( - linear, - left top, - left bottom, - color-stop(0, #3e648d), - color-stop(1, #405a6a) - ); - background-image: -o-linear-gradient(bottom, #3e648d 0%, #405a6a 100%); - background-image: -moz-linear-gradient(bottom, #3e648d 0%, #405a6a 100%); - background-image: -webkit-linear-gradient(bottom, #3e648d 0%, #405a6a 100%); - background-image: -ms-linear-gradient(bottom, #3e648d 0%, #405a6a 100%); - background-image: linear-gradient(to bottom, #3e648d 0%, #405a6a 100%); -} -.bs-header p { - font-weight: 300; - line-height: 1.5; -} -.bs-header .container { - position: relative; -} -.bs-header p, .bs-header h1 { - color: white; - text-shadow: - -1px -1px 0 #000, - 1px -1px 0 #000, - -1px 1px 0 #000, - 1px 1px 0 #000; -} - -@media (min-width: 768px) { - .bs-header { - font-size: 21px; - text-align: left; - } - .bs-header h1 { - font-size: 60px; - line-height: 1; - } -} - -@media (min-width: 992px) { - .bs-header p { - margin-right: 380px; - } -} - -.tooltip-inner { - font-size: medium; -} - -span.anchor { - margin-top: -70px; /* Size of fixed header */ - padding-bottom: 70px; - height: 0px; - display: block; -} - -.tr-first-in-group { - border-top: 2px solid; - border-color: lightgray; - padding-top: 10px; -} - -/* To hide the empty python index */ - -#indices-and-tables { - visibility: hidden; - display: none; -} - -.jumbotron { - position: relative; -} -.jumbotron canvas { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: #e9ecef; -} -.jumbotron .container { - pointer-events: none; - position: relative; - z-index: 10; -} -.jumbotron .container .btn { - margin-bottom: 0.25em; - pointer-events: auto; -} - - diff --git a/doc/jekyll_tools/css/pydoctor.css b/doc/jekyll_tools/css/pydoctor.css deleted file mode 100644 index 18c3e03b9..000000000 --- a/doc/jekyll_tools/css/pydoctor.css +++ /dev/null @@ -1,399 +0,0 @@ -.pydoctor-navbar { - margin-bottom: 0px; -} - -.page-header { - margin-top: 22px; - position: sticky; - top: 0; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: baseline; - background-color: #fff; - margin-bottom: 3px; - border-bottom: 0; - box-shadow: 0px 0px 8px 8px #fff; -} -.page-header h1 { - margin-bottom: 0; -} - -.categoryHeader { - font-size: 24px; - color: #777; - margin-bottom: 1.8em; -} - -a[name] { - position: relative; - bottom: 80px; - font-size: 0; -} - -.bs-docs-container ul { - margin-top: 10px; - padding-left: 10px; -} - -.bs-docs-container li { - padding-top: 5px; - padding-bottom: 5px; -} - -.bs-docs-container li a { - text-decoration: none; -} - -.bs-docs-container ul { - margin-left: 10px; -} - -.bs-docs-container ul ul { - border-left-color: #e1f5fe; - border-left-width: 1px; - border-left-style: solid; -} - -.bs-docs-container ul ul ul { - border-left-color: #b3e5fc; -} - -.bs-docs-container ul ul ul ul { - border-left-color: #81d4fa; -} - -.bs-docs-container ul ul ul ul ul { - border-left-color: #4fc3f7; -} - -.bs-docs-container ul ul ul ul ul ul { - border-left-color: #29b6f6; -} - -.bs-docs-container ul ul ul ul ul ul ul { - border-left-color: #03a9f4; -} - -.bs-docs-container ul ul ul ul ul ul ul ul { - border-left-color: #039be5; -} - -.pre { - white-space: pre; -} - -.undocumented { - font-style: italic; - color: #9e9e9e; -} - -.functionBody p { - margin-top: 6px; - margin-bottom: 6px; -} - -#splitTables > p { - margin-bottom: 5px; -} - -#splitTables > table, .fieldTable { - margin-bottom: 20px; - width: 100%; - border: 0; -} - -#splitTables > table { - border: 1px solid #eee; -} - -#splitTables > table tr { - border-bottom-color: #eee; - border-bottom-width: 1px; - border-bottom-style: solid; -} - -#splitTables > table tr td, .fieldTable tr td { - padding: 5px; -} - -#splitTables > table tr td { - border-left-color: #eee; - border-left-width: 1px; - border-left-style: solid; -} - -#splitTables > table tr td:nth-child(1), .fieldTable tr td:nth-child(1) { - border-left: none; - width: 150px; -} - -#splitTables > table tr td:nth-child(2), .fieldTable tr td.fieldArg { - width: 200px; -} - -tr.package { - background-color: #fff3e0; -} - -tr.module { - background-color: #fff8e1; -} - -tr.class, tr.classvariable, tr.baseclassvariable { - background-color: #fffde7; -} - -tr.instancevariable, tr.baseinstancevariable, tr.variable, tr.attribute, tr.property { - background-color: #f3e5f5; -} - -tr.interface { - background-color: #fbe9e7; -} - -tr.method, tr.function, tr.basemethod, tr.baseclassmethod, tr.classmethod { - background-color: #f1f8e9; -} - -tr.private { - background-color: #f1f1f1; -} - -.fieldTable { - margin-top: 10px; -} - -.fieldName { - font-weight: bold; -} - - -#childList > div { - margin: 10px; - padding: 10px; - padding-bottom: 5px; -} - -.functionBody { - margin-left: 15px; -} - -.functionBody > #part { - font-style: italic; -} - -.functionBody > #part > a { - text-decoration: none; -} - -.functionBody .interfaceinfo { - font-style: italic; - margin-bottom: 3px; -} - -.functionBody > .undocumented { - - margin-top: 6px; - margin-bottom: 6px; -} - -/* -- Links to class/function/etc names are nested like this: - label - This applies to inline docstring content marked up as code, - for example L{foo} in epytext or `bar` in restructuredtext, - but also to links that are present in summary tables. -- 'functionHeader' is used for lines like `def func():` and `var =` -*/ -code, .pre, #childList > div .functionHeader, -#splitTables > table tr td:nth-child(2), .fieldTable tr td.fieldArg { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} -code, #childList > div .functionHeader, .fieldTable tr td.fieldArg { - font-size: 90%; - color: #222222; -} -code > a { - color:#c7254e; - background-color:#f9f2f4; -} -/* top navagation bar */ -.page-header > h1 { - margin-top: 0; -} -.page-header > h1 > code { - color: #971c3a; -} - -/* -This defines the code style, it's black on light gray. -It also overwrite the default values inherited from bootstrap min -*/ -code { - padding:2px 4px; - background-color: #f4f4f4; - border-radius:4px -} - - -a.functionSourceLink { - font-weight: normal; -} - - -#childList > div { - border-left-color: #03a9f4; - border-left-width: 1px; - border-left-style: solid; - background: #fafafa; -} - -.moduleDocstring { - margin: 20px; -} - -#partOf { - margin-top: -13px; - margin-bottom: 19px; -} - -.fromInitPy { - font-style: italic; -} - -pre { - padding-left: 0px; -} - -/* Private stuff */ - -body.private-hidden #splitTables .private, -body.private-hidden #childList .private, -body.private-hidden #summaryTree .private { - /* changed because we don't want to hide members that pydoctor considers - * private; currently igraph._igraph.GraphBase is private according to - * pydoctor because of the underscore */ - /* display: none; */ -} - -#showPrivate { - padding: 10px; -} - -#current-docs-container { - font-style: italic; - padding-top: 11px; -} - -/* Deprecation stuff */ - -.deprecationNotice { - margin: 10px; -} - -/* Syntax highlighting for source code */ - -.py-string { - color: #337ab7; -} -.py-comment { - color: #309078; - font-style: italic; -} -.py-keyword { - font-weight: bold; -} -.py-defname { - color: #a947b8; - font-weight: bold; -} -.py-builtin { - color: #fc7844; - font-weight: bold; -} - -/* Doctest */ - -pre.py-doctest { - padding: .5em; -} -.py-prompt, .py-more { - color: #a8a8a8; -} -.py-output { - color: #c7254e; -} - -/* Admonitions */ - -div.rst-admonition p.rst-admonition-title:after { - content: ":"; -} - -div.rst-admonition p.rst-admonition-title { - margin: 0; - padding: 0.1em 0 0.35em 0em; - font-weight: bold; -} - -div.rst-admonition p.rst-admonition-title { - color: #333333; -} - -div.rst-admonition { - padding: 8px; - margin-bottom: 20px; - background-color: #EEE; - border: 1px solid #CCC; - border-radius: 4px; -} - -div.warning, div.attention, div.danger, div.error, div.caution { - background-color: #ffcf9cb0; - border: 1px solid #ffbbaa; -} - -div.danger p.rst-admonition-title, div.error p.rst-admonition-title, div.caution p.rst-admonition-title { - color: #b94a48; -} - -div.tip p.rst-admonition-title, div.hint p.rst-admonition-title, div.important p.rst-admonition-title{ - color: #3a87ad; -} - -div.tip, div.hint, div.important { - background-color: #d9edf7; - border-color: #bce8f1; -} - - -/* igraph-specific customizations follow from here */ - -.pydoctor-navbar { - display: none; -} - -table.fieldTable tr td { - vertical-align: baseline; -} - -.moduleDocstring { - margin: 20px 0; -} - -.page-header h1 { - font-size: 24px; -} -.categoryHeader { - font-size: 18px !important; - padding: 0 0 0 8px; -} -#showPrivate { - display: none; -} -.undocumented { - font-style: normal !important; -} - - diff --git a/doc/jekyll_tools/css/syntax.css b/doc/jekyll_tools/css/syntax.css deleted file mode 100644 index 67e6ea397..000000000 --- a/doc/jekyll_tools/css/syntax.css +++ /dev/null @@ -1,61 +0,0 @@ -.hll { background-color: #ffffcc } -.c { color: #408080; font-style: italic } /* Comment */ -.err { border: 1px solid #FF0000 } /* Error */ -.k { color: #008000; font-weight: bold } /* Keyword */ -.o { color: #666666 } /* Operator */ -.cm { color: #408080; font-style: italic } /* Comment.Multiline */ -.cp { color: #BC7A00 } /* Comment.Preproc */ -.c1 { color: #408080; font-style: italic } /* Comment.Single */ -.cs { color: #408080; font-style: italic } /* Comment.Special */ -.gd { color: #A00000 } /* Generic.Deleted */ -.ge { font-style: italic } /* Generic.Emph */ -.gr { color: #FF0000 } /* Generic.Error */ -.gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.gi { color: #00A000 } /* Generic.Inserted */ -.go { color: #888888 } /* Generic.Output */ -.gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.gs { font-weight: bold } /* Generic.Strong */ -.gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.gt { color: #0044DD } /* Generic.Traceback */ -.kc { color: #008000; font-weight: bold } /* Keyword.Constant */ -.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ -.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ -.kp { color: #008000 } /* Keyword.Pseudo */ -.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ -.kt { color: #B00040 } /* Keyword.Type */ -.m { color: #666666 } /* Literal.Number */ -.s { color: #BA2121 } /* Literal.String */ -.na { color: #7D9029 } /* Name.Attribute */ -.nb { color: #008000 } /* Name.Builtin */ -.nc { color: #0000FF; font-weight: bold } /* Name.Class */ -.no { color: #880000 } /* Name.Constant */ -.nd { color: #AA22FF } /* Name.Decorator */ -.ni { color: #999999; font-weight: bold } /* Name.Entity */ -.ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -.nf { color: #0000FF } /* Name.Function */ -.nl { color: #A0A000 } /* Name.Label */ -.nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -.nt { color: #008000; font-weight: bold } /* Name.Tag */ -.nv { color: #19177C } /* Name.Variable */ -.ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -.w { color: #bbbbbb } /* Text.Whitespace */ -.mf { color: #666666 } /* Literal.Number.Float */ -.mh { color: #666666 } /* Literal.Number.Hex */ -.mi { color: #666666 } /* Literal.Number.Integer */ -.mo { color: #666666 } /* Literal.Number.Oct */ -.sb { color: #BA2121 } /* Literal.String.Backtick */ -.sc { color: #BA2121 } /* Literal.String.Char */ -.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ -.s2 { color: #BA2121 } /* Literal.String.Double */ -.se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -.sh { color: #BA2121 } /* Literal.String.Heredoc */ -.si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -.sx { color: #008000 } /* Literal.String.Other */ -.sr { color: #BB6688 } /* Literal.String.Regex */ -.s1 { color: #BA2121 } /* Literal.String.Single */ -.ss { color: #19177C } /* Literal.String.Symbol */ -.bp { color: #008000 } /* Name.Builtin.Pseudo */ -.vc { color: #19177C } /* Name.Variable.Class */ -.vg { color: #19177C } /* Name.Variable.Global */ -.vi { color: #19177C } /* Name.Variable.Instance */ -.il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/doc/jekyll_tools/favicon.ico b/doc/jekyll_tools/favicon.ico deleted file mode 100644 index df709da1a..000000000 Binary files a/doc/jekyll_tools/favicon.ico and /dev/null differ diff --git a/doc/jekyll_tools/favicon.svg b/doc/jekyll_tools/favicon.svg deleted file mode 100644 index 6b2569802..000000000 --- a/doc/jekyll_tools/favicon.svg +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - logo-black - - - - - - - - - - - - diff --git a/doc/jekyll_tools/fonts/fonts.css b/doc/jekyll_tools/fonts/fonts.css deleted file mode 100644 index d4776e902..000000000 --- a/doc/jekyll_tools/fonts/fonts.css +++ /dev/null @@ -1,32 +0,0 @@ -@font-face { - font-family: 'rlogo'; - src:url('/https/github.com/fonts/rlogo.eot'); - src:url('/https/github.com/fonts/rlogo.eot?#iefix') format('embedded-opentype'), - url('/fonts/rlogo.ttf') format('truetype'), - url('/fonts/rlogo.woff') format('woff'), - url('/fonts/rlogo.svg#rlogo') format('svg'); - font-weight: normal; - font-style: normal; -} - -[class*="icon-rlogo"], [class*="icon-rlogo-alt"] { - font-family: 'rlogo'; - speak: none; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - color: auto; - - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.icon-rlogo:before { - content: "\e600"; -} -.icon-rlogo-alt:before { - content: "\e601"; -} diff --git a/doc/jekyll_tools/img/igraph_logo_black.svg b/doc/jekyll_tools/img/igraph_logo_black.svg deleted file mode 100644 index 410ffa84d..000000000 --- a/doc/jekyll_tools/img/igraph_logo_black.svg +++ /dev/null @@ -1 +0,0 @@ -logo-black \ No newline at end of file diff --git a/doc/jekyll_tools/img/igraph_logo_white.svg b/doc/jekyll_tools/img/igraph_logo_white.svg deleted file mode 100644 index cada6f592..000000000 --- a/doc/jekyll_tools/img/igraph_logo_white.svg +++ /dev/null @@ -1 +0,0 @@ -logo-white \ No newline at end of file diff --git a/doc/jekyll_tools/js/affix.js b/doc/jekyll_tools/js/affix.js deleted file mode 100644 index a94c76253..000000000 --- a/doc/jekyll_tools/js/affix.js +++ /dev/null @@ -1,10 +0,0 @@ - -var $window = $(window); -var $body = $(document.body); - -$body.scrollspy({ target: '.bs-sidebar' }); - -$window.on('load', function () { - $body.scrollspy('refresh'); -}); - diff --git a/doc/jekyll_tools/js/html5shiv.js b/doc/jekyll_tools/js/html5shiv.js deleted file mode 100644 index 784f221ca..000000000 --- a/doc/jekyll_tools/js/html5shiv.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - HTML5 Shiv v3.6.2pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed -*/ -(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); -a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; -c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| -"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",version:"3.6.2pre",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment(); -for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d