diff --git a/.clang-tidy b/.clang-tidy index 06dedeeb97..915afc9169 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -40,6 +40,7 @@ Checks: "-*, misc-*, -misc-non-private-member-variables-in-classes, -misc-no-recursion, + -misc-include-cleaner, modernize-*, -modernize-pass-by-value, @@ -51,15 +52,18 @@ Checks: "-*, -modernize-avoid-bind, performance-*, + -performance-avoid-endl, readability-*, -readability-braces-around-statements, + -readability-else-after-return, + -readability-function-cognitive-complexity, -readability-identifier-length, -readability-magic-numbers, -readability-redundant-access-specifiers, - -readability-function-cognitive-complexity, - -readability-else-after-return, -readability-uppercase-literal-suffix, + -readability-use-anyofallof, + -readability-avoid-const-params-in-decls, " WarningsAsErrors: '' HeaderFilterRegex: '^((?!/thirdparty/|/_deps/).)*$' diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f8ad7a506a..a31850bb7a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -118,7 +118,7 @@ body: Platform : x64 ------------------------- CONFIGURATION -------------------------- - Default INI : C:\ProgramData\eCAL\ecal.ini + Default YAML : C:\ProgramData\eCAL\ecal.yaml ------------------------- NETWORK -------------------------------- Host name : FRLBJRXW diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index db0f46f389..cf9cede085 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,10 +4,3 @@ ### Related issues - - -### Cherry-pick to - diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index e9107be8b8..de9f641135 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -8,38 +8,27 @@ on: jobs: build-macos: - runs-on: macos-latest + runs-on: macos-13 steps: - - name: Downgrade Python version - uses: actions/setup-python@v4 - id: cp39 - with: - python-version: '3.9' + # XProtect can cause random failures if it decides that the DMG we create + # during the packaging phase is malware. + # See https://github.com/actions/runner-images/issues/7522 and https://github.com/servo/servo/pull/30779 + - name: Kill XProtectBehaviorService + run: | + echo Killing XProtect.; sudo pkill -9 XProtect >/dev/null || true; + + - name: Install latest Python3 via brew + run: brew install python3 || brew link --overwrite python@3.12 - - name: Install Qt - uses: jurplel/install-qt-action@v3 - with: - setup-python: false - version: '5.15.2' - target: 'desktop' + - name: Install latest Qt5 via brew + run: brew install qt@5 - name: Install Dependencies - run: brew install ninja doxygen graphviz protobuf hdf5@1.10 pkg-config - - - name: Install Cap’n Proto - run: | - mkdir "${{ runner.workspace }}/capnp" - cd "${{ runner.workspace }}/capnp" - curl -O https://capnproto.org/capnproto-c++-0.9.0.tar.gz - tar zxf capnproto-c++-0.9.0.tar.gz - cd capnproto-c++-0.9.0 - ./configure - make -j - sudo make install + run: brew install ninja doxygen graphviz protobuf hdf5@1.10 pkg-config capnp - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: 'true' fetch-depth: 0 @@ -49,13 +38,14 @@ jobs: - name: Install Python requirements run: | - sudo pip3 install -r "$GITHUB_WORKSPACE/doc/requirements.txt" + sudo pip3 install -r "$GITHUB_WORKSPACE/doc/requirements.txt" --break-system-packages - name: CMake run: | mkdir "${{ runner.workspace }}/_build" cd "${{ runner.workspace }}/_build" cmake $GITHUB_WORKSPACE -G "Ninja" \ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake \ -DHAS_HDF5=ON \ -DHAS_QT5=ON \ -DHAS_CURL=ON \ @@ -68,9 +58,7 @@ jobs: -DBUILD_PY_BINDING=ON \ -DBUILD_CSHARP_BINDING=OFF \ -DBUILD_ECAL_TESTS=ON \ - -DECAL_INCLUDE_PY_SAMPLES=OFF \ -DECAL_INSTALL_SAMPLE_SOURCES=ON \ - -DECAL_JOIN_MULTICAST_TWICE=OFF \ -DECAL_NPCAP_SUPPORT=OFF \ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON \ -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ @@ -83,23 +71,22 @@ jobs: -DECAL_THIRDPARTY_BUILD_RECYCLE=ON \ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON \ -DECAL_THIRDPARTY_BUILD_QWT=ON \ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=ON \ -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH=/usr/local/opt/hdf5@1.10 \ + -DCMAKE_PREFIX_PATH="/usr/local/opt/hdf5@1.10;/usr/local/opt/qt@5" \ -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_FIND_PACKAGE_PREFER_CONFIG=ON \ -DPython_FIND_STRATEGY=LOCATION \ - -DPython_FIND_REGISTRY=NEVER - sudo mkdir /etc/ecal - sudo cp "$GITHUB_WORKSPACE/ecal/core/cfg/ecal.ini" /etc/ecal + -DPython_FIND_REGISTRY=NEVER shell: bash - name: Build Release run: cmake --build . --config Release working-directory: ${{ runner.workspace }}/_build - - - name: Build Python Wheel - run: cmake --build . --target create_python_wheel --config Release + + - name: Create config path and copy ecal.yaml + run: | + sudo mkdir /etc/ecal + sudo cp "./ecal/core/cfg/gen/ecal.yaml" /etc/ecal working-directory: ${{ runner.workspace }}/_build # - name: Build Documentation C @@ -115,18 +102,17 @@ jobs: # run: ctest -V # working-directory: ${{ runner.workspace }}/_build - - name: Pack - run: cpack -G DragNDrop - working-directory: ${{ runner.workspace }}/_build - - - name: Upload DMG - uses: actions/upload-artifact@v3 - with: - name: macos-dmg - path: ${{ runner.workspace }}/_build/_deploy/*.dmg - - - name: Upload Python Wheel - uses: actions/upload-artifact@v3 - with: - name: macos-python-wheel - path: ${{ runner.workspace }}/_build/_deploy/*.whl +# Currently (2024-11-28) packing very often fails under macos +# - name: Pack +# uses: nick-fields/retry@v2 +# with: +# max_attempts: 3 +# retry_on: error +# timeout_minutes: 3 +# command: cd ${{ runner.workspace }}/_build && cpack -G DragNDrop + +# - name: Upload DMG +# uses: actions/upload-artifact@v4 +# with: +# name: macos-dmg +# path: ${{ runner.workspace }}/_build/_deploy/*.dmg diff --git a/.github/workflows/build-ubuntu-20.yml b/.github/workflows/build-ubuntu-20.yml deleted file mode 100644 index f56f5e574e..0000000000 --- a/.github/workflows/build-ubuntu-20.yml +++ /dev/null @@ -1,193 +0,0 @@ -name: Build Ubuntu 20.04 - -on: - push: - pull_request: - branches: - - master - -jobs: - build-ubuntu: - runs-on: ubuntu-20.04 - - env: - # enable starting Qt GUI Applications - QT_QPA_PLATFORM: offscreen - - steps: - - name: Install Dependencies - run: | - sudo apt update - sudo apt-get install ninja-build doxygen graphviz libcurl4-openssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev qt5-default libqwt-qt5-dev libyaml-cpp-dev - - - name: Install Cap'n Proto - run: | - mkdir "${{ runner.workspace }}/capnp" - cd "${{ runner.workspace }}/capnp" - curl -O https://capnproto.org/capnproto-c++-0.9.0.tar.gz - tar zxf capnproto-c++-0.9.0.tar.gz - cd capnproto-c++-0.9.0 - ./configure - make -j - sudo make install - - - name: Checkout - uses: actions/checkout@v3 - with: - submodules: 'true' - fetch-depth: 0 - - - name: Install Python requirements - shell: bash - run: | - sudo apt-get -y install python3-dev python3-venv - mkdir ".venv_build" - python3 -m venv ".venv_build" - source ".venv_build/bin/activate" - pip install --upgrade pip - pip install wheel setuptools - pip install -r "$GITHUB_WORKSPACE/doc/requirements.txt" - - - name: CMake - run: | - source ".venv_build/bin/activate" - - export CC=/usr/bin/gcc-9 - export CXX=/usr/bin/g++-9 - mkdir "${{ runner.workspace }}/_build" - cd "${{ runner.workspace }}/_build" - - cmake $GITHUB_WORKSPACE -G "Ninja" \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - -DHAS_HDF5=ON \ - -DHAS_QT=ON \ - -DHAS_CURL=ON \ - -DHAS_CAPNPROTO=ON \ - -DHAS_FTXUI=ON \ - -DBUILD_DOCS=ON \ - -DBUILD_APPS=ON \ - -DBUILD_SAMPLES=ON \ - -DBUILD_TIME=ON \ - -DBUILD_PY_BINDING=ON \ - -DBUILD_STANDALONE_PY_WHEEL=ON \ - -DBUILD_CSHARP_BINDING=OFF \ - -DBUILD_ECAL_TESTS=ON \ - -DECAL_INCLUDE_PY_SAMPLES=OFF \ - -DECAL_INSTALL_SAMPLE_SOURCES=ON \ - -DECAL_JOIN_MULTICAST_TWICE=OFF \ - -DECAL_NPCAP_SUPPORT=OFF \ - -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON \ - -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ - -DECAL_THIRDPARTY_BUILD_SPDLOG=ON \ - -DECAL_THIRDPARTY_BUILD_TINYXML2=ON \ - -DECAL_THIRDPARTY_BUILD_FINEFTP=ON \ - -DECAL_THIRDPARTY_BUILD_CURL=OFF \ - -DECAL_THIRDPARTY_BUILD_GTEST=ON \ - -DECAL_THIRDPARTY_BUILD_HDF5=OFF \ - -DECAL_THIRDPARTY_BUILD_RECYCLE=ON \ - -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON \ - -DECAL_THIRDPARTY_BUILD_QWT=OFF \ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_SYSCONFDIR=/etc \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ - -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu \ - -DPython_FIND_VIRTUALENV=ONLY - - sudo mkdir /etc/ecal - sudo cp "$GITHUB_WORKSPACE/ecal/core/cfg/ecal.ini" /etc/ecal - shell: bash - - - name: Build Release - run: cmake --build . --config Release -- -k 0 - working-directory: ${{ runner.workspace }}/_build - - # Create Python Wheels - # The strang-looking double-cmake is an ugly workaround to force CMake to - # re-find Python, after we have changed the venv from the outside. The - # alternative would be to clean everything, which would cause an unnecessary - # rebuild of eCAL for each python Version. - - name: Build Python 3.9 Wheel - run: | - sudo apt-get -y install python3.9-dev python3.9-venv - mkdir ".venv_39" - python3.9 -m venv ".venv_39" - source ".venv_39/bin/activate" - pip install --upgrade pip - pip install wheel setuptools - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=FIRST - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: bash - working-directory: ${{ runner.workspace }}/_build - - - name: Build Python 3.8 Wheel - run: | - sudo apt-get -y install python3.8-dev python3.8-venv - mkdir ".venv_38" - python3.8 -m venv ".venv_38" - source ".venv_38/bin/activate" - pip install --upgrade pip - pip install wheel setuptools - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=FIRST - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: bash - working-directory: ${{ runner.workspace }}/_build - - - name: Run Tests - run: ctest -V - working-directory: ${{ runner.workspace }}/_build - - - name: Pack - run: cpack -G DEB - working-directory: ${{ runner.workspace }}/_build - - - name: Upload Debian - uses: actions/upload-artifact@v3 - with: - name: ubuntu-debian - path: ${{ runner.workspace }}/_build/_deploy/*.deb - - - name: Upload Python Wheel - uses: actions/upload-artifact@v3 - with: - name: ubuntu-python-wheel - path: ${{ runner.workspace }}/_build/_deploy/*.whl - - #--------------------------------------------------------------------------- - - # GNU tar - Excluding Some Files - # https://www.gnu.org/software/tar/manual/html_node/exclude.html - # the emtpy '.git/' drectory is required, it marks the root directory - - name: 'Create a tarball' - run: | - cd ${{ runner.workspace }} - tar --exclude-vcs-ignore \ - --exclude='bin' \ - --exclude='doc' \ - --exclude='_build/_CPack_Packages' \ - --exclude='_build/_deploy' \ - --exclude='_build/lib' \ - --exclude='_build/python' \ - --exclude='*.deb' \ - --exclude='*.a' \ - --exclude='*.o' \ - --exclude='*.so' \ - --exclude=ecal/.git/* \ - -czf ecal.tar.gz ecal/ _build/ - du -sh ecal.tar.gz - - - # https://github.com/actions/upload-artifact - - name: Upload the whole directory - uses: actions/upload-artifact@v3 - with: - name: ecal-dir - path: ${{ runner.workspace }}/ecal.tar.gz - - call-clang-tidy: - if: github.event_name == 'pull_request' - needs: build-ubuntu - uses: ./.github/workflows/run-clang-tidy.yml diff --git a/.github/workflows/build-ubuntu-22.yml b/.github/workflows/build-ubuntu-22.yml deleted file mode 100644 index 24b6903dcc..0000000000 --- a/.github/workflows/build-ubuntu-22.yml +++ /dev/null @@ -1,157 +0,0 @@ -name: Build Ubuntu 22.04 - -on: - push: - pull_request: - branches: - - master - -jobs: - build-ubuntu: - runs-on: ubuntu-22.04 - - env: - # enable starting Qt GUI Applications - QT_QPA_PLATFORM: offscreen - - steps: - - name: Install Dependencies - run: | - sudo apt update - sudo apt-get install ninja-build doxygen graphviz libcurl4-openssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev qtbase5-dev libqwt-qt5-dev libyaml-cpp-dev - - - - name: Install Cap'n Proto - run: | - mkdir "${{ runner.workspace }}/capnp" - cd "${{ runner.workspace }}/capnp" - curl -O https://capnproto.org/capnproto-c++-0.9.0.tar.gz - tar zxf capnproto-c++-0.9.0.tar.gz - cd capnproto-c++-0.9.0 - ./configure - make -j - sudo make install - - - name: Checkout - uses: actions/checkout@v3 - with: - submodules: 'true' - fetch-depth: 0 - - - name: Install Python requirements - shell: bash - run: | - sudo apt-get -y install python3-dev python3-venv - mkdir ".venv_build" - python3 -m venv ".venv_build" - source ".venv_build/bin/activate" - pip install --upgrade pip - pip install wheel setuptools - pip install -r "$GITHUB_WORKSPACE/doc/requirements.txt" - - - name: CMake - run: | - source ".venv_build/bin/activate" - - export CC=/usr/bin/gcc-11 - export CXX=/usr/bin/g++-11 - mkdir "${{ runner.workspace }}/_build" - cd "${{ runner.workspace }}/_build" - cmake $GITHUB_WORKSPACE -G "Ninja" \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ - -DHAS_HDF5=ON \ - -DHAS_QT=ON \ - -DHAS_CURL=ON \ - -DHAS_CAPNPROTO=ON \ - -DHAS_FTXUI=ON \ - -DBUILD_DOCS=ON \ - -DBUILD_APPS=ON \ - -DBUILD_SAMPLES=ON \ - -DBUILD_TIME=ON \ - -DBUILD_PY_BINDING=ON \ - -DBUILD_STANDALONE_PY_WHEEL=ON \ - -DBUILD_CSHARP_BINDING=OFF \ - -DBUILD_ECAL_TESTS=ON \ - -DECAL_INCLUDE_PY_SAMPLES=OFF \ - -DECAL_INSTALL_SAMPLE_SOURCES=ON \ - -DECAL_JOIN_MULTICAST_TWICE=OFF \ - -DECAL_NPCAP_SUPPORT=OFF \ - -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON \ - -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ - -DECAL_THIRDPARTY_BUILD_SPDLOG=ON \ - -DECAL_THIRDPARTY_BUILD_TINYXML2=ON \ - -DECAL_THIRDPARTY_BUILD_FINEFTP=ON \ - -DECAL_THIRDPARTY_BUILD_CURL=OFF \ - -DECAL_THIRDPARTY_BUILD_GTEST=ON \ - -DECAL_THIRDPARTY_BUILD_HDF5=OFF \ - -DECAL_THIRDPARTY_BUILD_RECYCLE=ON \ - -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON \ - -DECAL_THIRDPARTY_BUILD_QWT=OFF \ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_SYSCONFDIR=/etc \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ - -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu \ - -DPython_FIND_VIRTUALENV=ONLY - - sudo mkdir /etc/ecal - sudo cp "$GITHUB_WORKSPACE/ecal/core/cfg/ecal.ini" /etc/ecal - shell: bash - - - name: Build Release - run: cmake --build . --config Release -- -k 0 - working-directory: ${{ runner.workspace }}/_build - - # Create Python Wheels - # The strang-looking double-cmake is an ugly workaround to force CMake to - # re-find Python, after we have changed the venv from the outside. The - # alternative would be to clean everything, which would cause an unnecessary - # rebuild of eCAL for each python Version. - - name: Build Python 3.11 Wheel - run: | - sudo apt-get -y install python3.11-dev python3.11-venv - mkdir ".venv_311" - python3.11 -m venv ".venv_311" - source ".venv_311/bin/activate" - pip install --upgrade pip - pip install wheel setuptools - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=FIRST - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: bash - working-directory: ${{ runner.workspace }}/_build - - - name: Build Python 3.10 Wheel - run: | - sudo apt-get -y install python3.10-dev python3.10-venv - mkdir ".venv_310" - python3.10 -m venv ".venv_310" - source ".venv_310/bin/activate" - pip install --upgrade pip - pip install wheel setuptools - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=FIRST - cmake $GITHUB_WORKSPACE -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: bash - working-directory: ${{ runner.workspace }}/_build - - - name: Run Tests - run: ctest -V - working-directory: ${{ runner.workspace }}/_build - - - name: Pack - run: cpack -G DEB - working-directory: ${{ runner.workspace }}/_build - - - name: Upload Debian - uses: actions/upload-artifact@v3 - with: - name: ubuntu-debian - path: ${{ runner.workspace }}/_build/_deploy/*.deb - - - name: Upload Python Wheel - uses: actions/upload-artifact@v3 - with: - name: ubuntu-python-wheel - path: ${{ runner.workspace }}/_build/_deploy/*.whl diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml new file mode 100644 index 0000000000..29c61a580d --- /dev/null +++ b/.github/workflows/build-ubuntu.yml @@ -0,0 +1,186 @@ +name: Build Ubuntu + +on: + push: + pull_request: + +jobs: + build-ubuntu: + + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04] + + runs-on: ${{ matrix.os }} + + env: + # enable starting Qt GUI Applications + QT_QPA_PLATFORM: offscreen + PROJECT_NAME: ecal + + steps: + + - name: Install Dependencies + run: | + sudo apt update + + if [ "${{ matrix.os }}" == "ubuntu-24.04" ]; then + sudo apt-get install ninja-build doxygen graphviz libcurl4-openssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev libyaml-cpp-dev + sudo apt-get install qt6-base-dev qt6-svg-dev + sudo apt-get install libgtest-dev + sudo apt-get install python3 python3-venv python3-dev + elif [ "${{ matrix.os }}" == "ubuntu-22.04" ]; then + sudo apt-get install ninja-build doxygen graphviz libcurl4-openssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev libyaml-cpp-dev + sudo apt-get install qtbase5-dev libqt5opengl5-dev libqt5svg5-dev + sudo apt-get install libgtest-dev + sudo apt-get install python3 python3-venv python3-dev + elif [ "${{ matrix.os }}" == "ubuntu-20.04" ]; then + sudo apt-get install ninja-build doxygen graphviz libcurl4-openssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev libyaml-cpp-dev + sudo apt-get install qt5-default libqt5opengl5-dev libqt5svg5-dev + sudo apt-get install libgtest-dev + sudo apt-get install python3.9 python3.9-venv python3.9-dev + fi + + - name: Set variables + run: | + if [ "${{ matrix.os }}" == "ubuntu-24.04" ]; then + echo "ubuntu_codename=noble" >> "$GITHUB_ENV" + echo "python_version=3" >> "$GITHUB_ENV" # => default python 3 version + elif [ "${{ matrix.os }}" == "ubuntu-22.04" ]; then + echo "ubuntu_codename=jammy" >> "$GITHUB_ENV" + echo "python_version=3" >> "$GITHUB_ENV" # => default python 3 version + elif [ "${{ matrix.os }}" == "ubuntu-20.04" ]; then + echo "ubuntu_codename=focal" >> "$GITHUB_ENV" + echo "python_version=3.9" >> "$GITHUB_ENV" + fi + + # Get cpu architecture + echo "cpu_architecture=$(dpkg --print-architecture)" >> "$GITHUB_ENV" + + - name: Install Cap'n Proto + run: | + mkdir "${{ runner.workspace }}/capnp" + cd "${{ runner.workspace }}/capnp" + curl -O https://capnproto.org/capnproto-c++-1.0.2.tar.gz + tar zxf capnproto-c++-1.0.2.tar.gz + cd capnproto-c++-1.0.2 + ./configure + make -j$(($(nproc)*2)) + sudo make install + + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'false' + fetch-depth: 0 + + - name: Update / download Submodules (selected ones) + run: | + cd $GITHUB_WORKSPACE + git submodule init + git submodule deinit thirdparty/curl/curl + git submodule deinit thirdparty/hdf5/hdf5 + git submodule deinit thirdparty/protobuf/protobuf + git submodule update + + - name: Create venv for building docs + shell: bash + run: | + mkdir ".venv_build" + python${{ env.python_version }} -m venv ".venv_build" + source ".venv_build/bin/activate" + pip install --upgrade pip + pip install wheel setuptools + pip install -r "$GITHUB_WORKSPACE/doc/requirements.txt" + + - name: CMake + run: | + source ".venv_build/bin/activate" + + mkdir "${{ runner.workspace }}/_build" + cd "${{ runner.workspace }}/_build" + + cmake $GITHUB_WORKSPACE -G "Ninja" \ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DHAS_HDF5=ON \ + -DHAS_QT=ON \ + -DHAS_CURL=ON \ + -DHAS_CAPNPROTO=ON \ + -DHAS_FTXUI=ON \ + -DBUILD_DOCS=ON \ + -DBUILD_APPS=ON \ + -DBUILD_SAMPLES=ON \ + -DBUILD_TIME=ON \ + -DBUILD_PY_BINDING=ON \ + -DBUILD_STANDALONE_PY_WHEEL=OFF \ + -DBUILD_CSHARP_BINDING=OFF \ + -DBUILD_ECAL_TESTS=ON \ + -DECAL_INSTALL_SAMPLE_SOURCES=ON \ + -DECAL_NPCAP_SUPPORT=OFF \ + -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON \ + -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ + -DECAL_THIRDPARTY_BUILD_SPDLOG=ON \ + -DECAL_THIRDPARTY_BUILD_TINYXML2=ON \ + -DECAL_THIRDPARTY_BUILD_FINEFTP=ON \ + -DECAL_THIRDPARTY_BUILD_CURL=OFF \ + -DECAL_THIRDPARTY_BUILD_GTEST=ON \ + -DECAL_THIRDPARTY_BUILD_HDF5=OFF \ + -DECAL_THIRDPARTY_BUILD_RECYCLE=ON \ + -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON \ + -DECAL_THIRDPARTY_BUILD_QWT=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_SYSCONFDIR=/etc \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INSTALL_LOCALSTATEDIR=/var \ + -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu \ + -DPython_FIND_VIRTUALENV=ONLY + shell: bash + + - name: Build Release + run: cmake --build . --parallel -- -k 0 + working-directory: ${{ runner.workspace }}/_build + + - name: Create config path and copy ecal.yaml + run: | + sudo mkdir /etc/ecal + sudo cp "./ecal/core/cfg/gen/ecal.yaml" /etc/ecal + working-directory: ${{ runner.workspace }}/_build + shell: bash + + - name: Run Tests + run: ctest -V + working-directory: ${{ runner.workspace }}/_build + + - name: Get Project version from git tag + shell: bash + run: | + # Use git describe to get the tag / commit description + VERSION="$(git describe --tags --dirty)" + + # Remove the leading 'v' from the tag + VERSION="${VERSION#v}" + + echo "PROJECT_VERSION=$VERSION" >> "$GITHUB_ENV" + + - name: Set output binary name + shell: bash + run: | + echo "BINARY_NAME=${{ env.PROJECT_NAME }}_${{ env.PROJECT_VERSION }}-${{ env.ubuntu_codename }}_${{ env.cpu_architecture }}" >> "$GITHUB_ENV" + + - name: CPack + run: cpack -G DEB + working-directory: ${{ runner.workspace }}/_build + + - name: Rename .deb installer + run: | + mv *.deb '${{ env.BINARY_NAME }}.deb' + shell: bash + working-directory: ${{runner.workspace}}/_build/_deploy/ + + - name: Upload Debian + uses: actions/upload-artifact@v4 + with: + name: '${{ env.BINARY_NAME }}' + path: ${{ runner.workspace }}/_build/_deploy/*.deb diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index ba2b72a918..3a74d5a1f3 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -1,4 +1,4 @@ -name: Build Windows Server 2019 +name: Build Windows on: push: @@ -6,7 +6,6 @@ on: branches: - master env: - IS_GITHUB_SIGNING_ALLOWED: true IS_JENKINS_SIGNING_ALLOWED: true jobs: @@ -26,46 +25,19 @@ jobs: target: 'desktop' arch: 'win64_msvc2019_64' - # Downgrading nuget is required as of 2021-04-23, as nuget 5.9.1.111 fails installing protobuf - # https://github.com/actions/virtual-environments/issues/3240 - - name: Downgrade nuget - uses: nuget/setup-nuget@v1 - with: - nuget-version: '5.8.x' - - name: Install Dependencies - # choco install of version 1.9.3 produced a checksum error - run: choco install doxygen.install --version=1.9.2 + # Pin to latest doxygen version. + run: choco install doxygen.install --version=1.13.2 - name: Uninstall Chocolatey run: move "$env:PROGRAMDATA\chocolatey" "$env:PROGRAMDATA\_chocolatey" -# - name: Install Cap’n Proto -# run: | -# mkdir "${{ runner.workspace }}/capnp" -# cd "${{ runner.workspace }}/capnp" -# git clone https://github.com/sandstorm-io/capnproto.git -# cd capnproto -# git checkout release-0.9.0 -# cd c++ -# mkdir _build -# cd _build -# cmake .. -G "Visual Studio 16 2019" -A x64 -# cmake --build . --parallel --config Release -# cmake --build . --target install --config Release - - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: 'true' fetch-depth: 0 - - name: Download NPCAP - run: | - cd %GITHUB_WORKSPACE% - powershell -Command "& 'build_win\download_npcap.ps1'" - shell: cmd - - name: Create Python virtualenv run: | mkdir "${{ runner.workspace }}\_build\complete\.venv\" @@ -90,6 +62,7 @@ jobs: cd "${{ runner.workspace }}/_build/sdk" cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 ^ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake ^ -DHAS_HDF5=ON ^ -DHAS_QT=ON ^ -DHAS_CURL=OFF ^ @@ -102,9 +75,7 @@ jobs: -DBUILD_PY_BINDING=OFF ^ -DBUILD_CSHARP_BINDING=OFF ^ -DBUILD_ECAL_TESTS=OFF ^ - -DECAL_INCLUDE_PY_SAMPLES=OFF ^ -DECAL_INSTALL_SAMPLE_SOURCES=OFF ^ - -DECAL_JOIN_MULTICAST_TWICE=OFF ^ -DECAL_NPCAP_SUPPORT=ON ^ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON ^ -DECAL_THIRDPARTY_BUILD_PROTOBUF=ON ^ @@ -117,7 +88,6 @@ jobs: -DECAL_THIRDPARTY_BUILD_RECYCLE=ON ^ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON ^ -DECAL_THIRDPARTY_BUILD_QWT=OFF ^ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF ^ -DECAL_THIRDPARTY_BUILD_UDPCAP=ON ^ -DBUILD_SHARED_LIBS=OFF ^ -DCMAKE_PREFIX_PATH="%ProgramFiles%/Cap'n Proto/lib/cmake/CapnProto" ^ @@ -130,6 +100,7 @@ jobs: CALL "${{ runner.workspace }}\.venv\Scripts\activate.bat" cd "${{ runner.workspace }}/_build/complete" cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 ^ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake ^ -DHAS_HDF5=ON ^ -DHAS_QT=ON ^ -DHAS_CURL=ON ^ @@ -139,12 +110,10 @@ jobs: -DBUILD_APPS=ON ^ -DBUILD_SAMPLES=ON ^ -DBUILD_TIME=ON ^ - -DBUILD_PY_BINDING=ON ^ + -DBUILD_PY_BINDING=OFF ^ -DBUILD_CSHARP_BINDING=ON ^ -DBUILD_ECAL_TESTS=ON ^ - -DECAL_INCLUDE_PY_SAMPLES=OFF ^ -DECAL_INSTALL_SAMPLE_SOURCES=ON ^ - -DECAL_JOIN_MULTICAST_TWICE=OFF ^ -DECAL_NPCAP_SUPPORT=ON ^ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON ^ -DECAL_THIRDPARTY_BUILD_PROTOBUF=ON ^ @@ -157,14 +126,11 @@ jobs: -DECAL_THIRDPARTY_BUILD_RECYCLE=ON ^ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON ^ -DECAL_THIRDPARTY_BUILD_QWT=ON ^ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=ON ^ -DECAL_THIRDPARTY_BUILD_UDPCAP=ON ^ -DBUILD_SHARED_LIBS=OFF ^ -DCMAKE_PREFIX_PATH="%ProgramFiles%/Cap'n Proto/lib/cmake/CapnProto" ^ -DCMAKE_BUILD_TYPE=Release ^ - -DCPACK_PACK_WITH_INNOSETUP=ON - mkdir "%ALLUSERSPROFILE%\eCAL" - copy "%GITHUB_WORKSPACE%\ecal\core\cfg\ecal.ini" "%ALLUSERSPROFILE%\eCAL" + -DCPACK_PACK_WITH_INNOSETUP=ON shell: cmd - name: Build SDK @@ -175,91 +141,13 @@ jobs: run: cmake --build . --config Release working-directory: ${{ runner.workspace }}/_build/complete - # Create Python. - # The strang-looking double-cmake is an ugly workaround to force CMake to - # re-find Python, after we have changed the venv from the outside. The - # alternative would be to clean everything, which would cause an unnecessary - # rebuild of eCAL and HDF5 for each python Version. - - name: Build Python 3.12 Wheel - run: | - mkdir ".venv_312" - py -3.12 -m venv ".venv_312" - CALL ".venv_312\Scripts\activate.bat" - pip install wheel setuptools - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=FIRST - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: cmd - working-directory: ${{ runner.workspace }}/_build/complete - - - name: Build Python 3.11 Wheel - run: | - mkdir ".venv_311" - py -3.11 -m venv ".venv_311" - CALL ".venv_311\Scripts\activate.bat" - pip install wheel - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=FIRST - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: cmd - working-directory: ${{ runner.workspace }}/_build/complete - - - name: Build Python 3.10 Wheel - run: | - mkdir ".venv_310" - py -3.10 -m venv ".venv_310" - CALL ".venv_310\Scripts\activate.bat" - pip install wheel - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=FIRST - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: cmd - working-directory: ${{ runner.workspace }}/_build/complete - - - name: Build Python 3.9 Wheel + - name: Create config path and copy ecal.yaml run: | - mkdir ".venv_39" - py -3.9 -m venv ".venv_39" - CALL ".venv_39\Scripts\activate.bat" - pip install wheel - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=FIRST - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: cmd - working-directory: ${{ runner.workspace }}/_build/complete - - - name: Build Python 3.8 Wheel - run: | - mkdir ".venv_38" - py -3.8 -m venv ".venv_38" - CALL ".venv_38\Scripts\activate.bat" - pip install wheel - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=FIRST - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release - shell: cmd + mkdir "%ALLUSERSPROFILE%\eCAL" + copy ".\ecal\core\cfg\gen\ecal.yaml" "%ALLUSERSPROFILE%\eCAL" working-directory: ${{ runner.workspace }}/_build/complete - - - name: Build Python 3.7 Wheel - run: | - mkdir ".venv_37" - py -3.7 -m venv ".venv_37" - CALL ".venv_37\Scripts\activate.bat" - pip install wheel - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=FIRST - cmake %GITHUB_WORKSPACE% -G "Visual Studio 16 2019" -A x64 -T v142 -DPython_FIND_VIRTUALENV=ONLY - cmake --build . --target create_python_wheel --config Release shell: cmd - working-directory: ${{ runner.workspace }}/_build/complete - -# - name: Build Documentation C -# run: cmake --build . --target documentation_c -# working-directory: ${{ runner.workspace }}/_build -# -# - name: Build Documentation C++ -# run: cmake --build . --target documentation_cpp -# working-directory: ${{ runner.workspace }}/_build - + - name: Run Tests run: ctest -C Release -V working-directory: ${{ runner.workspace }}/_build/complete @@ -272,48 +160,53 @@ jobs: run: cpack -C Release working-directory: ${{ runner.workspace }}/_build/complete - - name: Detect certificate - id: cert - if: env.IS_GITHUB_SIGNING_ALLOWED == 'true' + - name: Get Project version from git tag + shell: powershell run: | - if ($Env:CERT_BODY -and $Env:CERT_PSWD -and $Env:CERT_ALGO -and $Env:CERT_HASH) { - Write-Output "ATTENTION: a certificate is available" - Write-Output "IS_GITHUB_SIGNING_ENABLED=true" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append - } else { - Write-Output "WARNING: a certificate is not available" - } - env: - CERT_BODY: ${{ secrets.CERT_BODY }} - CERT_PSWD: ${{ secrets.CERT_PSWD }} - CERT_ALGO: ${{ secrets.CERT_ALGO }} - CERT_HASH: ${{ secrets.CERT_HASH }} - - # https://github.com/OrhanKupusoglu/code-sign-action - - name: Sign the installer - if: env.IS_GITHUB_SIGNING_ENABLED == 'true' - uses: OrhanKupusoglu/code-sign-action@v5.5.1 - with: - cert_body: ${{ secrets.CERT_BODY }} - cert_pswd: ${{ secrets.CERT_PSWD }} - cert_algo: ${{ secrets.CERT_ALGO }} - cert_hash: ${{ secrets.CERT_HASH }} - folder: ${{ runner.workspace }}/_build/complete/_deploy - debug: false + # Use git describe to get the tag / commit description + $VERSION = git describe --tags --dirty + + #remove the leading 'v' from the tag, if it exists + $VERSION = $VERSION -replace '^v', '' + + echo "VERSION=$VERSION" >> "$Env:GITHUB_ENV" + + - name: Set output binary name + shell: powershell + run: | + $BINARY_NAME = "ecal_${{ env.VERSION }}-win64" + echo "BINARY_NAME=$BINARY_NAME" >> "$Env:GITHUB_ENV" + + - name: Rename the setup exe + shell: powershell + run: | + $LS_OUT = ls *.exe + $SETUP_NAME = "$($LS_OUT.Name)" + Rename-Item -Path "$SETUP_NAME" -NewName "${{ env.BINARY_NAME }}.exe" + working-directory: ${{ runner.workspace }}/_build/complete/_deploy/ - name: Upload Windows setup - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: windows-setup + name: unsigned-setup path: ${{ runner.workspace }}/_build/complete/_deploy/*.exe - - name: Upload Python Wheels - uses: actions/upload-artifact@v3 - with: - name: windows-python-wheels - path: ${{ runner.workspace }}/_build/complete/_deploy/*.whl - # -------------------------------------------------------------------------------------------------- + sign-windows-installer: + if: github.repository == 'eclipse-ecal/ecal' + runs-on: windows-2019 + needs: build-windows + + steps: + + # Download the installer from the previous job + - name: Download Windows setup + uses: actions/download-artifact@v4 + with: + name: unsigned-setup + path: ${{ runner.workspace }}/_build/complete/_deploy + - name: Sign the installer on Eclipse CI if: env.IS_JENKINS_SIGNING_ALLOWED == 'true' && env.JENKINS_USERNAME != '' && env.JENKINS_API_TOKEN != '' && env.JENKINS_JOB_TOKEN != '' run: | @@ -326,8 +219,8 @@ jobs: $JENKINS_CRUMB_URL = "$JENKINS_BASE_URL/crumbIssuer/api/json" $JENKINS_JOB_URL = "$JENKINS_BASE_URL/job/$JENKINS_JOB" $JENKINS_TRIGGER_URL = "$JENKINS_JOB_URL/buildWithParameters?token=$Env:JENKINS_JOB_TOKEN" - $WAIT_FOR_JENKINS_SEC = 5 - $COUNTER_LIMIT = 20 + $WAIT_FOR_JENKINS_SEC = 10 + $COUNTER_LIMIT = 30 $RESPONSE_CODE = 0 $CRUMB_ID = '' $CRUMB_FIELD = '' @@ -481,9 +374,16 @@ jobs: JENKINS_JOB_TOKEN: ${{ secrets.JENKINS_TOKEN_GH_FILE }} working-directory: ${{ runner.workspace }}/_build/complete/_deploy + - name: Determine name of the installer for zip file + shell: powershell + run: | + $INSTALLER_NAME = "${{ env.ASSET_NAME }}" + $INSTALLER_NAME_WITHOUT_EXE = $INSTALLER_NAME.Substring(0, $INSTALLER_NAME.Length - 4) + echo "ARTIFACT_NAME=$INSTALLER_NAME_WITHOUT_EXE" >> "$Env:GITHUB_ENV" + - name: Upload Windows setup signed on Eclipse CI if: env.IS_DOWNLOAD_AVAILABLE == 'true' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: windows-setup-signed + name: ${{ env.ARTIFACT_NAME }} path: ${{ runner.workspace }}/_build/complete/_deploy/${{ env.ASSET_NAME }} diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml new file mode 100644 index 0000000000..7400ead64e --- /dev/null +++ b/.github/workflows/build_wheels.yml @@ -0,0 +1,66 @@ +name: Build Wheels + +on: + push: + branches: + - master + pull_request: + branches: + - master + release: + types: [published] + workflow_dispatch: + + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + fetch-depth: 0 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.21 + env: + CIBW_ARCHS: auto64 + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }} + path: ./wheelhouse/*.whl + + build_arm64_wheels: + # Emulation takes a long time so we save it for release/manual triggering + name: Build arm64 wheels via emulation + runs-on: ubuntu-latest + if: ${{ github.event_name != 'pull_request' }} + + steps: + - uses: actions/checkout@v4 + with: + submodules: 'true' + fetch-depth: 0 + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.21 + env: + CIBW_ARCHS_LINUX: aarch64 + + - uses: actions/upload-artifact@v4 + with: + name: cibw-wheels-arm64 + path: ./wheelhouse/*.whl + diff --git a/.github/workflows/cherry-pick-label-check.yml b/.github/workflows/cherry-pick-label-check.yml new file mode 100644 index 0000000000..46ef578082 --- /dev/null +++ b/.github/workflows/cherry-pick-label-check.yml @@ -0,0 +1,24 @@ +name: Cherry Pick Label Check + +on: + pull_request: + types: + - labeled + - unlabeled + - opened + - synchronize + branches: + - master + +jobs: + cherry-pick-label-check: + runs-on: ubuntu-latest + + steps: + - name: Check labels + run: | + labels=$(jq -r '.pull_request.labels[].name' $GITHUB_EVENT_PATH) + if [[ ! $labels == *cherry-pick-to-* ]]; then + echo "No label starting with 'cherry-pick-to-' found." + exit 1 + fi diff --git a/.github/workflows/cherry-pick-to.yml b/.github/workflows/cherry-pick-to.yml new file mode 100644 index 0000000000..02222f7901 --- /dev/null +++ b/.github/workflows/cherry-pick-to.yml @@ -0,0 +1,189 @@ +name: Cherry-pick-to-branch + +on: + push: + branches: [ "master" ] + +env: + cherry_pick_label_prefix: "cherry-pick-to-" + cherry_pick_pr_success_label: "Auto cherry-pick success ✅" + cherry_pick_pr_failure_label: "Auto cherry-pick failure ⚠️" + use_draft_pr: "true" + +jobs: + cherry-pick-from-push: + strategy: + matrix: + target-branch: [ "support/v5.12", "support/v5.13" ] + + runs-on: ubuntu-latest + + steps: + + - name: Setup Variables + id: setup + run: | + echo continue_workflow=true >> $GITHUB_ENV + short_sha=$(echo ${{ github.event.after }} | cut -c1-7) + echo cherry_pick_branch=cherry-pick/$short_sha/${{matrix.target-branch}} >> $GITHUB_ENV + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.CHERRY_PICK_GITHUB_TOKEN }} # This token was created on 2024-03-26 and is valid for 1 year: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues/4466#note_1987666 + + - name: Determine PR number (if any) + id: pr + run: | + pr_number=$(gh pr list --search ${{ github.event.after }} --state merged --json number --jq '.[0].number') + echo "PR number: $pr_number" + echo pr_number=$pr_number >> $GITHUB_OUTPUT + + # Set the continue workflow to false, if the pr_number is empty + if [ -z "$pr_number" ]; then + echo continue_workflow=false >> $GITHUB_ENV + fi + env: + GITHUB_TOKEN: ${{ secrets.CHERRY_PICK_GITHUB_TOKEN }} # This token was created on 2024-03-26 and is valid for 1 year: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues/4466#note_1987666 + + - name: Check for a cherry pick label and save whether that is the case + if: ${{ env.continue_workflow == 'true' }} + run: | + # List all labels for the PR number from the last step + labels=$(gh pr view ${{ steps.pr.outputs.pr_number }} --json labels --jq '.labels[].name') + + echo "Labels: $labels" + + # Check if the list contains the special cherry pick label + if [[ $labels == *"${{ env.cherry_pick_label_prefix }}${{matrix.target-branch}}"* ]]; then + echo "Cherry pick label found" + echo continue_workflow=true >> $GITHUB_ENV + else + echo "Cherry pick label not found" + echo continue_workflow=false >> $GITHUB_ENV + fi + env: + GITHUB_TOKEN: ${{ secrets.CHERRY_PICK_GITHUB_TOKEN }} + + - name: Create new branch for cherry picking + if: ${{ env.continue_workflow == 'true' }} + run: | + # Set the git config to the pr_author and pr_author_email + git config user.name '${{ github.event.pusher.name }}' + git config user.email '${{ github.event.pusher.email }}' + + git checkout ${{ matrix.target-branch }} + git checkout -b ${{ env.cherry_pick_branch }} + + - name: Cherry pick the commit between the before (exclusive) and after (inclusive) commits + id: cherry-pick + if: ${{ env.continue_workflow == 'true' }} + run: | + git cherry-pick ${{ github.event.before }}..${{ github.event.after }} + continue-on-error: true + + - name: Create PR description + if: ${{ env.continue_workflow == 'true' }} + id: pr-description + run: | + # Determine original PR title + original_pr_title=$(gh pr view ${{ steps.pr.outputs.pr_number }} --json title --jq '.title') + + # Create a title for the new PR + echo pr_title="[CP #${{ steps.pr.outputs.pr_number }} > ${{ matrix.target-branch }}] $original_pr_title" >> $GITHUB_OUTPUT + + if [ "${{ steps.cherry-pick.outcome }}" == "success" ]; then + echo pr_label="${{ env.cherry_pick_pr_success_label }}" >> $GITHUB_OUTPUT + + echo pr_draft_command="" >> $GITHUB_OUTPUT + + # Create multiline pr_description + echo "pr_description<> $GITHUB_OUTPUT + echo "# Cherry-pick" >> $GITHUB_OUTPUT + echo "Cherry-picked PR #${{ steps.pr.outputs.pr_number }} to branch \`${{ matrix.target-branch }}\`." >> $GITHUB_OUTPUT + echo "The cherry-pick was **successful**." >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "Please review the changes and **rebase-merge** if desired." >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + else + + echo pr_label="${{ env.cherry_pick_pr_failure_label }}" >> $GITHUB_OUTPUT + + # Only set the pr_draft_command if the use_draft_pr is true. Otherwise, set it to an empty string. + # Some repos (like personal ones) might not have the draft PR feature enabled. + if [ "${{ env.use_draft_pr }}" == "true" ]; then + echo pr_draft_command="--draft" >> $GITHUB_OUTPUT + else + echo pr_draft_command="" >> $GITHUB_OUTPUT + fi + + # Create multiline pr_description + echo "pr_description<> $GITHUB_OUTPUT + echo "# Cherry-pick failed" >> $GITHUB_OUTPUT + echo "Cherry-picked PR #${{ steps.pr.outputs.pr_number }} to branch \`${{ matrix.target-branch }}\`." >> $GITHUB_OUTPUT + echo "The cherry-pick has **failed**." >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "The following files have caused conflicts:" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "\`\`\`bash" >> $GITHUB_OUTPUT + git diff --name-only --diff-filter=U >> $GITHUB_OUTPUT + echo "\`\`\`" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "## Resolving" >> $GITHUB_OUTPUT + echo "Please resolve conflicts manually. You can use this PR and branch to your convenience." >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "\`\`\`bash" >> $GITHUB_OUTPUT + echo "git fetch origin" >> $GITHUB_OUTPUT + echo "git checkout -b local/${{ env.cherry_pick_branch }} origin/${{ matrix.target-branch }}" >> $GITHUB_OUTPUT + echo "git branch -u origin/${{ env.cherry_pick_branch }}" >> $GITHUB_OUTPUT + echo "git cherry-pick ${{ github.event.before }}..${{ github.event.after }}" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "# Resolve conflicts and use" >> $GITHUB_OUTPUT + echo "# git cherry-pick --continue" >> $GITHUB_OUTPUT + echo "# until all conflicts are resolved." >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "git push -f origin HEAD:${{ env.cherry_pick_branch }}" >> $GITHUB_OUTPUT + echo "\`\`\`" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo "After resolving all conflicts, **rebase-merge** this PR." >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + fi + env: + GITHUB_TOKEN: ${{ secrets.CHERRY_PICK_GITHUB_TOKEN }} + + # If the cherry-pick fails, abort the cherry-pick and create an empty commit on it. + - name: Abort cherry-pick if it failed and add empty commit for PR creation + if: ${{ env.continue_workflow == 'true' && steps.cherry-pick.outcome == 'failure' }} + run: | + git cherry-pick --abort + + # Use the bot user for the commit + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + + # Create an empty commit + git commit --allow-empty -m "Cherry-pick failed" + + git log --oneline -n 5 + + - name: Push the cherry-pick branch + if: ${{ env.continue_workflow == 'true' }} + run: git push origin ${{ env.cherry_pick_branch }} + + - name: create pull request + if: ${{ env.continue_workflow == 'true' }} + run: | + # Check if the label exists in the repository. If not, create it. + gh label list | grep -q "${{ steps.pr-description.outputs.pr_label }}" || gh label create "${{ steps.pr-description.outputs.pr_label }}" + + # Create the pull request + gh pr create -B '${{ matrix.target-branch }}' \ + -H '${{ env.cherry_pick_branch }}' \ + --title '${{ steps.pr-description.outputs.pr_title }}' \ + --body '${{ steps.pr-description.outputs.pr_description }}' \ + --label '${{ steps.pr-description.outputs.pr_label }}' \ + ${{ steps.pr-description.outputs.pr_draft_command }} + env: + GITHUB_TOKEN: ${{ secrets.CHERRY_PICK_GITHUB_TOKEN }} diff --git a/.github/workflows/clang-tidy-review-post-comments.yml b/.github/workflows/clang-tidy-review-post-comments.yml index e9fcc46531..13da89510d 100644 --- a/.github/workflows/clang-tidy-review-post-comments.yml +++ b/.github/workflows/clang-tidy-review-post-comments.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: ZedThree/clang-tidy-review/post@v0.14.0 + - uses: ZedThree/clang-tidy-review/post@v0.20.1 # lgtm_comment_body, max_comments, and annotations need to be set on the posting workflow in a split setup with: # adjust options as necessary diff --git a/.github/workflows/clang-tidy-review.yml b/.github/workflows/clang-tidy-review.yml index 4e8cb6a279..0ee377b1bb 100644 --- a/.github/workflows/clang-tidy-review.yml +++ b/.github/workflows/clang-tidy-review.yml @@ -26,21 +26,22 @@ jobs: fetch-depth: 0 - name: Run clang-tidy - uses: ZedThree/clang-tidy-review@v0.14.0 + uses: ZedThree/clang-tidy-review@v0.20.1 id: review with: build_dir: _build apt_packages: "cmake,ninja-build,build-essential,zlib1g-dev,qtbase5-dev,libhdf5-dev,libprotobuf-dev,libprotoc-dev,protobuf-compiler,libcurl4-openssl-dev,libqwt-qt5-dev,libyaml-cpp-dev" config_file: ".clang-tidy" - exclude: "thirdparty/*,_build/*,convert_utf.cpp,convert_utf.h,testing/*" + exclude: "ecal/core/src/serialization/nanopb/*,thirdparty/*,_build/*,convert_utf.cpp,convert_utf.h,tests/*" split_workflow: true lgtm_comment_body: "" cmake_command: | cmake . -B _build \ -G Ninja \ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DHAS_HDF5=ON \ - -DHAS_QT5=ON \ + -DHAS_QT=ON \ -DHAS_CURL=ON \ -DHAS_CAPNPROTO=OFF \ -DHAS_FTXUI=ON \ @@ -52,9 +53,7 @@ jobs: -DBUILD_STANDALONE_PY_WHEEL=OFF \ -DBUILD_CSHARP_BINDING=OFF \ -DBUILD_ECAL_TESTS=OFF \ - -DECAL_INCLUDE_PY_SAMPLES=OFF \ -DECAL_INSTALL_SAMPLE_SOURCES=ON \ - -DECAL_JOIN_MULTICAST_TWICE=OFF \ -DECAL_NPCAP_SUPPORT=OFF \ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON \ -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ @@ -67,7 +66,6 @@ jobs: -DECAL_THIRDPARTY_BUILD_RECYCLE=ON \ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON \ -DECAL_THIRDPARTY_BUILD_QWT=OFF \ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_PREFIX=/usr \ @@ -75,4 +73,4 @@ jobs: -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu cmake --build _build - - uses: ZedThree/clang-tidy-review/upload@v0.14.0 + - uses: ZedThree/clang-tidy-review/upload@v0.20.1 diff --git a/.github/workflows/documentation-release-page.yml b/.github/workflows/documentation-release-page.yml new file mode 100644 index 0000000000..6472ad3255 --- /dev/null +++ b/.github/workflows/documentation-release-page.yml @@ -0,0 +1,77 @@ +name: Documentation Release Page + +on: + push: + + release: + types: + - released + - unpublished + - deleted + +jobs: + documentation-release-page: + runs-on: ubuntu-latest + + steps: + + - name: Get current branch name + id: branch + run: | + # Get the branch name + branch=$(echo ${GITHUB_REF#refs/heads/}) + + # only publish documentation for master branch + if [[ $branch == master ]]; then + echo "publish_doc=true" >> $GITHUB_ENV + else + echo "publish_doc=false" >> $GITHUB_ENV + fi + + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'false' + fetch-depth: 0 + + + - name: Install Python + run: | + sudo apt update + sudo apt-get -y install python3-dev python3-venv + + - name: Install Python dependencies + run: | + mkdir ".venv" + python3 -m venv ".venv" + source ".venv/bin/activate" + pip install --upgrade pip + pip install -r "$GITHUB_WORKSPACE/doc/requirements.txt" + + - name: Build Release page with Sphinx + env: + ECAL_GH_API_KEY: ${{ secrets.GITHUB_TOKEN }} + run: | + source ".venv/bin/activate" + sphinx-build -b html doc/release_page build/html + + - name: Zip Release Page + run: | + cd build/html + zip -r ../release-page.zip . + + - name: Upload documentation + uses: actions/upload-artifact@v4 + with: + name: release-page + path: build/release-page.zip + + - name: Deploy Release Page + uses: peaceiris/actions-gh-pages@v3 + with: + publish_branch: gh-pages + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: build/html + destination_dir: releases + if: env.publish_doc == 'true' + \ No newline at end of file diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 0a3a86cd34..4994ad946f 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -2,31 +2,58 @@ name: Documentation build on: push: - branches: - - master - release: - types: - - released - - unpublished - - deleted + + # release: + # types: + # - released + # - unpublished + # - deleted jobs: documentation-build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: + - name: Get current branch name + id: branch + run: | + # Get the branch name + branch=$(echo ${GITHUB_REF#refs/heads/}) + + # if the branch is a support/ branch, then set the doc_version + if [[ $branch == support/* ]]; then + echo "doc_version=$(echo ${branch#support/})" >> $GITHUB_ENV + echo "publish_dir=$(echo ${branch#support/})" >> $GITHUB_ENV + echo "publish_doc=true" >> $GITHUB_ENV + elif [[ $branch == master ]]; then + echo "doc_version=v999.0" >> $GITHUB_ENV + echo "publish_dir=latest" >> $GITHUB_ENV + echo "publish_doc=true" >> $GITHUB_ENV + else + echo "publish_doc=false" >> $GITHUB_ENV + fi + - name: Install Dependencies run: | sudo apt update sudo apt-get install ninja-build doxygen graphviz libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: - submodules: 'true' + submodules: 'false' fetch-depth: 0 - ref: 'master' - + + - name: Update / download Submodules (selected ones) + run: | + cd $GITHUB_WORKSPACE + git submodule init + git submodule deinit thirdparty/curl/curl + git submodule deinit thirdparty/gtest/googletest + git submodule deinit thirdparty/hdf5/hdf5 + git submodule deinit thirdparty/protobuf/protobuf + git submodule update + - name: Install Python requirements shell: bash run: | @@ -42,13 +69,12 @@ jobs: run: | source ".venv_build/bin/activate" - export CC=/usr/bin/gcc-9 - export CXX=/usr/bin/g++-9 mkdir "${{ runner.workspace }}/_build" cd "${{ runner.workspace }}/_build" cmake $GITHUB_WORKSPACE -G "Ninja" \ + -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake \ -DHAS_HDF5=ON \ - -DHAS_QT5=OFF \ + -DHAS_QT=OFF \ -DHAS_CURL=OFF \ -DHAS_CAPNPROTO=OFF \ -DHAS_FTXUI=ON \ @@ -59,9 +85,7 @@ jobs: -DBUILD_PY_BINDING=ON \ -DBUILD_CSHARP_BINDING=OFF \ -DBUILD_ECAL_TESTS=OFF \ - -DECAL_INCLUDE_PY_SAMPLES=OFF \ -DECAL_INSTALL_SAMPLE_SOURCES=OFF \ - -DECAL_JOIN_MULTICAST_TWICE=OFF \ -DECAL_NPCAP_SUPPORT=OFF \ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON \ -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ @@ -74,7 +98,6 @@ jobs: -DECAL_THIRDPARTY_BUILD_RECYCLE=ON \ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON \ -DECAL_THIRDPARTY_BUILD_QWT=OFF \ - -DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_SYSCONFDIR=/etc \ -DCMAKE_INSTALL_PREFIX=/usr \ @@ -86,12 +109,26 @@ jobs: - name: Build Documentation env: ECAL_GH_API_KEY: ${{ secrets.GITHUB_TOKEN }} + ECAL_DOC_VERSION: ${{ env.doc_version }} run: cmake --build . --parallel --config Release --target documentation_sphinx working-directory: ${{ runner.workspace }}/_build + - name: Zip Documentation + run: | + cd ${{ runner.workspace }}/_build/doc/html + zip -r ${{ runner.workspace }}/_build/doc/html.zip . + + - name: Upload Documentation as Artifact + uses: actions/upload-artifact@v4 + with: + name: documentation + path: ${{ runner.workspace }}/_build/doc/html.zip + - name: Deploy Documentation - uses: peaceiris/actions-gh-pages@v3.6.4 + uses: peaceiris/actions-gh-pages@v3 with: publish_branch: gh-pages github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ${{ runner.workspace }}/_build/doc/html + destination_dir: ${{ env.publish_dir }} + if: env.publish_doc == 'true' diff --git a/.github/workflows/ecal-fat-source.yml b/.github/workflows/ecal-fat-source.yml index ba23825c43..ae3d44314a 100644 --- a/.github/workflows/ecal-fat-source.yml +++ b/.github/workflows/ecal-fat-source.yml @@ -10,7 +10,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: 'true' fetch-depth: 0 @@ -68,7 +68,7 @@ jobs: shell: bash - name: Upload source - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ecal-fat-source path: ${{ runner.workspace }}/cleaned/ecal-fat-source.tar.gz diff --git a/.github/workflows/pr-auto-approve.yml b/.github/workflows/pr-auto-approve.yml index 24b6c60b9a..2166b95848 100644 --- a/.github/workflows/pr-auto-approve.yml +++ b/.github/workflows/pr-auto-approve.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: 'false' fetch-depth: 0 @@ -43,7 +43,7 @@ jobs: echo "${{ steps.protected-files-changes.outputs.all_changed_files }}" exit 1 - - uses: hmarr/auto-approve-action@v3 + - uses: hmarr/auto-approve-action@v4 if: steps.protected-files-changes.outputs.any_changed == 'false' with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/run-clang-tidy.yml b/.github/workflows/run-clang-tidy.yml deleted file mode 100644 index 60751dad4d..0000000000 --- a/.github/workflows/run-clang-tidy.yml +++ /dev/null @@ -1,72 +0,0 @@ -name: Run clang-tidy - -on: - workflow_call: - -jobs: - clang-tidy-scan: - runs-on: ubuntu-20.04 - continue-on-error: true - - steps: - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install ninja-build doxygen graphviz libcurl4-openssl-dev libprotobuf-dev libprotoc-dev protobuf-compiler libhdf5-dev qt5-default libyaml-cpp-dev - sudo apt-get install clang-tidy - - - name: Display version info - run: | - echo $(g++ --version) - echo $(clang --version) - echo $(cmake --version) - echo $(clang-tidy --version) - - # https://github.com/actions/download-artifact - - name: Download the built directory - uses: actions/download-artifact@v3 - with: - name: ecal-dir - - # replace the working directory - - name: Extract the tarball archive - run: mv ecal.tar.gz ../. && cd .. && rm -rf ecal && tar -xzf ecal.tar.gz && cd ecal - - # https://github.com/Ana06/get-changed-files - - name: Detect the changeset - id: changed_files - uses: Ana06/get-changed-files@v2.1.0 - - # see: ./build.sh --help - - name: Run clang-tidy on the changeset - id: suffix - run: | - build_linux/clang-tidy/build.sh -a -b ../../../_build -f ${{ steps.changed_files.outputs.added_modified }} - - # https://github.com/actions/upload-artifact - # If make or clang-tidy is never called, artifact upload will fail (no log files) with just a warning. - - name: Archive logs as artifact - uses: actions/upload-artifact@v3 - with: - name: clang_tidy_log_${{ steps.suffix.outputs.timestamp }} - path: ~/work/ecal/_build/clang_tidy_log_*.txt - if-no-files-found: warn - -# - name: Detect number of clang-tidy warnings -# id: num_warnings -# run: | -# NUM_WARNINGS=0 -# NUM_LOG_FILES=$(ls ~/work/ecal/_build/clang_tidy_log_*.txt 2> /dev/null | wc -l) -# if [[ ${NUM_LOG_FILES} -gt 0 ]] -# then -# NUM_WARNINGS=$(grep -oE "\w+\.\w+:\w+:\w+:\s?warning:\s?.*" -- ~/work/ecal/_build/clang_tidy_log_*.txt | wc -l) -# fi -# echo "::set-output name=value::${NUM_WARNINGS}" - -# # https://github.com/actions/github-script -# - name: Check clang-tidy warnings -# if: ${{ steps.num_warnings.outputs.value > 0 }} -# uses: actions/github-script@v6 -# with: -# script: | -# core.setFailed('number of clang-tidy warnings: ${{ steps.num_warnings.outputs.value}}') diff --git a/.gitignore b/.gitignore index ea4b4ed5d3..b1ced1794c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,12 +5,19 @@ Thumbs.db /_build* /_setup /_vs_out* +/out + +# Python building and distribution +/_python_build/ +/dist/ +/lang/python/core/ecal/_version.py +/wheelhouse/ # Binary libraries /thirdparty/npcap/ # autogenerated files -/ecal/include/ecal/ecal_defs.h +/ecal/include/ecal/defs.h # Doxygen output /doc/*.tmp @@ -41,6 +48,11 @@ doc/rst/_download_main_page doc/extensions/_autogen doc/rst/getting_started/**/*_pb2.py doc/rst/.venv +doc/release_page/index.rst +doc/release_page/ecal_*.rst +doc/release_page/changelog_*.txt +doc/release_page/_build +.venv/ *.pyc # Clion @@ -49,3 +61,10 @@ cmake-build-* # clang-tidy log_*.txt + +# User CMake Presets +CMakeUserPresets.json + +# Output of the scan-dependencies-with-dash.py script and the dash-licensing tool +/dependencies.txt +/summary.txt diff --git a/.gitmodules b/.gitmodules index fd27987533..cf64dadf89 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,6 @@ [submodule "thirdparty/tclap"] path = thirdparty/tclap/tclap url = https://github.com/xguerin/tclap.git -[submodule "thirdparty/simpleini"] - path = thirdparty/simpleini/simpleini - url = https://github.com/brofield/simpleini.git [submodule "thirdparty/spdlog"] path = thirdparty/spdlog/spdlog url = https://github.com/gabime/spdlog.git @@ -25,12 +22,6 @@ [submodule "thirdparty/curl"] path = thirdparty/curl/curl url = https://github.com/curl/curl.git -[submodule "thirdparty/zlib"] - path = thirdparty/zlib/zlib - url = https://github.com/madler/zlib.git -[submodule "thirdparty/libssh2"] - path = thirdparty/libssh2/libssh2 - url = https://github.com/libssh2/libssh2.git [submodule "thirdparty/hdf5"] path = thirdparty/hdf5/hdf5 url = https://github.com/HDFGroup/hdf5.git @@ -55,3 +46,6 @@ [submodule "thirdparty/udpcap"] path = thirdparty/udpcap/udpcap url = https://github.com/eclipse-ecal/udpcap.git +[submodule "thirdparty/ecaludp/ecaludp"] + path = thirdparty/ecaludp/ecaludp + url = https://github.com/eclipse-ecal/ecaludp.git diff --git a/CMakeLists.txt b/CMakeLists.txt index dc31c54ca8..d5f37b8ad6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -69,7 +69,6 @@ endif() # use it that way cmake .. -DBUILD_APPS=ON -DBUILD_SAMPLES=ON # -------------------------------------------------------- option(HAS_HDF5 "Platform supports HDF5 library" ON) -option(HAS_QT "Platform supports Qt 5 / 6 library." ON) # If the user set the legacy HAS_QT5 option, but didn't set the new HAS_QT option, set it to the value of HAS_QT5 if(DEFINED HAS_QT5 AND NOT DEFINED HAS_QT) @@ -77,56 +76,59 @@ if(DEFINED HAS_QT5 AND NOT DEFINED HAS_QT) message(WARNING "The option HAS_QT5 is deprecated and may be removed at any time. Please use HAS_QT instead.") endif() +option(HAS_QT "Platform supports Qt 5 / 6 library." ON) + option(HAS_CURL "Build with CURL (i.e. upload support in the recorder app)" ON) +option(HAS_FTXUI "Platform supports FTXUI library. Requires C++17 and up." ON) + +# Serialization format support option(HAS_CAPNPROTO "Platform supports Cap'n Proto library" OFF) option(HAS_FLATBUFFERS "Platform supports flatbuffers library" OFF) -option(HAS_FTXUI "Platform supports FTXUI library. Requires C++17 and up." ON) +option(HAS_MESSAGEPACK "Platform supports messagepack library" OFF) option(BUILD_DOCS "Build the eCAL documentation" OFF) option(BUILD_APPS "Build the eCAL applications" ON) +option(BUILD_APP_REC_ADDON_SDK "Build eCAL rec addon SDK" ${BUILD_APPS}) option(BUILD_SAMPLES "Build the eCAL samples" ON) option(BUILD_TIME "Build the eCAL time interfaces" ON) +option(BUILD_C_BINDING "Build eCAL C binding" ON) +mark_as_advanced(FORCE BUILD_C_BINDING) option(BUILD_PY_BINDING "Build eCAL python binding" OFF) -option(BUILD_STANDALONE_PY_WHEEL "Build eCAL python binding as standalone wheel" OFF) option(BUILD_CSHARP_BINDING "Build eCAL C# binding" OFF) option(BUILD_ECAL_TESTS "Build the eCAL google tests" OFF) -option(ECAL_INCLUDE_PY_SAMPLES "Include python language sample projects into CMake" OFF) option(ECAL_INSTALL_SAMPLE_SOURCES "Install the sources of eCAL samples" ON) option(ECAL_NPCAP_SUPPORT "Enable the eCAL Npcap Receiver (i.e. the Win10 performance fix)" OFF) option(ECAL_USE_CLOCKLOCK_MUTEX "Use native mutex with monotonic clock (requires glibc >= 2.30)" OFF) -# Set option regarding third party library builds -# option(ECAL_THIRDPARTY_BUILD_LIBSSH2 "Build libssh2 with eCAL" ON) -# option(ECAL_THIRDPARTY_BUILD_ZLIB "Build zlib with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_ASIO "Build asio with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS "Build CMakeFunctions with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_FINEFTP "Build fineFTP with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_FTXUI "Build ftxui with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_GTEST "Build gtest with eCAL" OFF) -option(ECAL_THIRDPARTY_BUILD_RECYCLE "Build steinwurf::recylce with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_SPDLOG "Build spdlog with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_SIMPLEINI "Build simpleini with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_TCLAP "Build tclap library with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_TCP_PUBSUB "Build tcp_pubsub library with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_TERMCOLOR "Build termcolor with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_TINYXML2 "Build tinyxml2 with eCAL" ON) -option(ECAL_THIRDPARTY_BUILD_UDPCAP "Build udpcap library with eCAL" OFF) +# -------------------------------------------------------- +# ecal core configuration +# -------------------------------------------------------- +set(ECAL_CORE_HAS_PROTOBUF ON) +set(ECAL_CORE_BUILD_SAMPLES ${BUILD_SAMPLES}) +set(ECAL_CORE_BUILD_TESTS ${BUILD_ECAL_TESTS}) +set(ECAL_CORE_CONFIGURATION ON) +set(ECAL_CORE_COMMAND_LINE ON) +set(ECAL_CORE_REGISTRATION ON) +set(ECAL_CORE_MONITORING ON) +set(ECAL_CORE_PUBLISHER ON) +set(ECAL_CORE_SUBSCRIBER ON) +set(ECAL_CORE_SERVICE ON) +set(ECAL_CORE_TIMEPLUGIN ON) +set(ECAL_CORE_NPCAP_SUPPORT ${ECAL_NPCAP_SUPPORT}) +set(ECAL_CORE_REGISTRATION_SHM ON) +set(ECAL_CORE_TRANSPORT_UDP ON) +set(ECAL_CORE_TRANSPORT_TCP ON) +set(ECAL_CORE_TRANSPORT_SHM ON) + +# ----------------------- +# eCAL Python configuration +# ----------------------- +#set(ECAL_PYTHON_BUILD_SAMPLES ${BUILD_SAMPLES}) +set(ECAL_PYTHON_BUILD_TESTS ${BUILD_ECAL_TESTS}) +set(ECAL_PYTHON_HAS_HDF5 ${HAS_HDF5}) -if(WIN32) - option(ECAL_THIRDPARTY_BUILD_PROTOBUF "Build protobuf with eCAL" ON) - option(ECAL_THIRDPARTY_BUILD_YAML-CPP "Build yaml-cpp with eCAL" ON) - option(ECAL_THIRDPARTY_BUILD_CURL "Build CURL with eCAL" ON) - option(ECAL_THIRDPARTY_BUILD_HDF5 "Build HDF5 with eCAL" ON) - cmake_dependent_option(ECAL_THIRDPARTY_BUILD_QWT "Build qwt::qwt with eCAL" ON "HAS_QT" OFF) -else() - option(ECAL_THIRDPARTY_BUILD_PROTOBUF "Build protobuf with eCAL" OFF) - option(ECAL_THIRDPARTY_BUILD_CURL "Build CURL with eCAL" OFF) - option(ECAL_THIRDPARTY_BUILD_HDF5 "Build HDF5 with eCAL" OFF) - cmake_dependent_option(ECAL_THIRDPARTY_BUILD_QWT "Build qwt::qwt with eCAL" OFF "HAS_QT" OFF) - option(ECAL_THIRDPARTY_BUILD_YAML-CPP "Build yaml-cpp with eCAL" OFF) -endif() # This should be ON, unless build ecal hdf5 for Matlab usage option(ECAL_LINK_HDF5_SHARED "Link shared libs of HDF5" ON) @@ -135,10 +137,20 @@ option(CPACK_PACK_WITH_INNOSETUP "Create Innosetup installer for t set(ECAL_INSTALL_PYTHON_DIR "bin" CACHE PATH "Location to install the Python extension modules. Might be set by setupdtools install.") -set(ECAL_BUILD_VERSION "0.0.0" CACHE STRING "Inject a build version if not building from a git repository") +if(DEFINED SKBUILD_PROJECT_VERSION) + message(STATUS + "Using version from scikit-build-core: ${SKBUILD_PROJECT_VERSION}" + ) + set(ECAL_BUILD_VERSION "${SKBUILD_PROJECT_VERSION}" CACHE STRING + "Version provided by scikit-build-core and setuptools-scm" FORCE + ) +else() + set(ECAL_BUILD_VERSION "0.0.0" CACHE STRING + "Inject a build version if not building from a git repository" + ) +endif() -set(ECAL_CSHARP_BUILD_SAMPLES ${BUILD_SAMPLES}) # there is a CMake issue with testing threading availibility via TEST_RUN @@ -146,12 +158,8 @@ if(${CMAKE_CROSSCOMPILING}) set(THREADS_PTHREAD_ARG "2" CACHE STRING "Forcibly set by CMakeLists.txt." FORCE) endif() - include(build_location) -# find_project(eCAL calls shall be ignored, eCAL is build as part of the project) -set(as_subproject eCAL) - if(CMAKE_EXPORT_COMPILE_COMMANDS) message(STATUS "Compilation database will be created") else() @@ -165,61 +173,6 @@ file(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH) message(STATUS "Module Path: ${CMAKE_MODULE_PATH}") message(STATUS "Prefix Path: ${CMAKE_PREFIX_PATH}") -if(MSVC) - message(STATUS "supress thirdparty warnings for windows platform ..") - set(CMAKE_CXX_FLAGS_OLD "${CMAKE_CXX_FLAGS}") - if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") - string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W0") - endif() -endif() - -# This is a list of subprojects, that might be build with eCAL -# according to how options ECAL_BUILD_ are set -set(possible_subprojects - asio - CMakeFunctions - CURL - fineftp - ftxui - GTest - HDF5 - #libssh2 - Protobuf - qwt - recycle - simpleini - spdlog - tclap - tcp_pubsub - termcolor - tinyxml2 - udpcap - yaml-cpp - #zlib zlibstatic -) - -# We should rename the option, but don't know how to do in in a -# backwards compatible way -set(ECAL_THIRDPARTY_BUILD_CMAKEFUNCTIONS ${ECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS}) - -# if a package does need to be build, include the cmake file with build instructions -foreach (dep IN LISTS possible_subprojects) - string(TOUPPER ${dep} dep_upper) - string(TOLOWER ${dep} dep_lower) - if (ECAL_THIRDPARTY_BUILD_${dep_upper}) - include(thirdparty/${dep_lower}/build-${dep_lower}.cmake) - endif () -endforeach () - -if(MSVC) - message(STATUS "reset thirdparty warnings for windows platform ..") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}") -endif() - -find_package(CMakeFunctions REQUIRED) - # -------------------------------------------------------- # detect qt library # -------------------------------------------------------- @@ -227,11 +180,13 @@ if(MSVC) if (HAS_QT) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core QUIET) if (NOT "${QT_FOUND}") + include("cmake/qt_msvc_path.cmake") autodetect_qt_msvc_dir() endif() endif() endif() +find_package(CMakeFunctions REQUIRED) git_revision_information(DEFAULT ${ECAL_BUILD_VERSION}) set(eCAL_VERSION_MAJOR ${GIT_REVISION_MAJOR}) @@ -240,17 +195,17 @@ set(eCAL_VERSION_PATCH ${GIT_REVISION_PATCH}) set(eCAL_VERSION_STRING ${eCAL_VERSION_MAJOR}.${eCAL_VERSION_MINOR}.${eCAL_VERSION_PATCH}) set(eCAL_VERSION ${eCAL_VERSION_STRING}) +message(STATUS "eCAL version: ${eCAL_VERSION_STRING}") +message(DEBUG "eCAL git describe tag: ${GIT_DESCRIBE_TAG}") + include(helper_functions/ecal_add_functions) include(helper_functions/ecal_helper_functions) include(helper_functions/ecal_install_functions) -include(helper_functions/ecal_python_functions) if(MSVC) set(eCAL_PLATFORM_TOOLSET ${CMAKE_VS_PLATFORM_TOOLSET}) endif() - - # -------------------------------------------------------- # offer the user the choice of overriding the installation directories # -------------------------------------------------------- @@ -303,21 +258,6 @@ if(WIN32) set(CMAKE_RELWITHDEBINFO_POSTFIX reldbg) endif() -# -------------------------------------------------------- -# protobuf utilities -# -------------------------------------------------------- -add_subdirectory(contrib/ecalproto) - -# -------------------------------------------------------- -# old ecal core protobuf interface (for compatibility) -# -------------------------------------------------------- -add_subdirectory(ecal/pb) - -# -------------------------------------------------------- -# ecal core protobuf interface -# -------------------------------------------------------- -add_subdirectory(ecal/core_pb) - # -------------------------------------------------------- # ecal app protobuf interface # -------------------------------------------------------- @@ -326,8 +266,7 @@ add_subdirectory(app/app_pb) # -------------------------------------------------------- # ecal core # -------------------------------------------------------- -add_subdirectory(ecal/service) -add_subdirectory(ecal/core) +add_subdirectory(ecal) # -------------------------------------------------------- # custom libs @@ -347,15 +286,17 @@ endif() # -------------------------------------------------------- # ecal mon plugin sdk # -------------------------------------------------------- -if(HAS_QT) +if(HAS_QT AND BUILD_APPS) add_subdirectory(app/mon/mon_plugin_lib) endif() # -------------------------------------------------------- # ecal rec addon sdk # -------------------------------------------------------- -add_subdirectory(app/rec/rec_addon_core) -add_subdirectory(app/rec/rec_addon_dummy) +if(BUILD_APP_REC_ADDON_SDK) + add_subdirectory(app/rec/rec_addon_core) + add_subdirectory(app/rec/rec_addon_dummy) +endif() # -------------------------------------------------------- # ecal time @@ -373,7 +314,6 @@ endif() if(HAS_HDF5) add_subdirectory(contrib/measurement/hdf5) add_subdirectory(contrib/ecalhdf5) - add_subdirectory(contrib/message) endif() add_subdirectory(contrib/measurement/base) @@ -388,14 +328,22 @@ endif() # ecal core csharp binding # -------------------------------------------------------- if(BUILD_CSHARP_BINDING AND WIN32) + set(ECAL_CSHARP_BUILD_SAMPLES ${BUILD_SAMPLES}) + set(ECAL_CSHARP_BUILD_TESTS ${BUILD_ECAL_TESTS}) add_subdirectory(lang/csharp) endif() +if(BUILD_C_BINDING) + set(ECAL_C_BUILD_SAMPLES ${BUILD_SAMPLES}) + set(ECAL_C_BUILD_TESTS ${BUILD_ECAL_TESTS}) + add_subdirectory(lang/c) +endif() + # -------------------------------------------------------- # console applications # -------------------------------------------------------- -add_subdirectory(app/apps) if(BUILD_APPS) + add_subdirectory(app/apps) if (HAS_FTXUI) add_subdirectory(app/mon/mon_tui) endif() @@ -456,6 +404,43 @@ if(BUILD_SAMPLES) add_subdirectory(samples) endif() + +# -------------------------------------------------------- +# Serialization extensions +# -------------------------------------------------------- +# Capnroto +if (HAS_CAPNPROTO) +set(ECAL_CAPNPROTO_BUILD_SAMPLES ${BUILD_SAMPLES}) +set(ECAL_CAPNPROTO_BUILD_TESTS ${BUILD_ECAL_TESTS}) +add_subdirectory(serialization/capnproto) +endif () + +# Flatbuffers +if (HAS_FLATBUFFERS) +set(ECAL_FLATBUFFERS_BUILD_SAMPLES ${BUILD_SAMPLES}) +set(ECAL_FLATBUFFERS_BUILD_TESTS ${BUILD_ECAL_TESTS}) +add_subdirectory(serialization/flatbuffers) +endif() + +# Messagepack +#if (HAS_MESSAGEPACK) +#set(ECAL_MESSAGEPACK_BUILD_SAMPLES ${BUILD_SAMPLES}) +#set(ECAL_MESSAGEPACK_BUILD_TESTS ${BUILD_ECAL_TESTS}) +#add_subdirectory(serialization/messagepack) +#endif() + +# Protobuf +set(ECAL_PROTOBUF_BUILD_SAMPLES ${BUILD_SAMPLES}) +set(ECAL_PROTOBUF_BUILD_TESTS ${BUILD_ECAL_TESTS}) +add_subdirectory(serialization/protobuf) + +# String +set(ECAL_STRING_BUILD_SAMPLES ${BUILD_SAMPLES}) +set(ECAL_STRING_BUILD_TESTS ${BUILD_ECAL_TESTS}) +add_subdirectory(serialization/string) + + + # -------------------------------------------------------- # unit tests # -------------------------------------------------------- @@ -466,26 +451,9 @@ if(BUILD_ECAL_TESTS) # test contrib # ------------------------------------------------------ if(HAS_HDF5) - add_subdirectory(testing/contrib/ecalhdf5/hdf5_test) + add_subdirectory(tests/contrib/ecalhdf5/hdf5_test) endif() - add_subdirectory(testing/contrib/ecalproto/dynproto_test) - add_subdirectory(testing/contrib/ecalproto/ecal_proto_test) - # ------------------------------------------------------ - # test ecal - # ------------------------------------------------------ - add_subdirectory(testing/ecal/clientserver_test) - - add_subdirectory(testing/ecal/core_test) - add_subdirectory(testing/ecal/event_test) - add_subdirectory(testing/ecal/expmap_test) - add_subdirectory(testing/ecal/io_memfile_test) - add_subdirectory(testing/ecal/pubsub_inproc_test) - add_subdirectory(testing/ecal/pubsub_proto_test) - add_subdirectory(testing/ecal/pubsub_test) - add_subdirectory(testing/ecal/topic2mcast_test) - add_subdirectory(testing/ecal/util_test) - # ------------------------------------------------------ # test apps # ------------------------------------------------------ @@ -494,11 +462,6 @@ if(BUILD_ECAL_TESTS) endif() endif() -# -------------------------------------------------------- -# configs -# -------------------------------------------------------- -add_subdirectory(ecal/core/cfg) - if(BUILD_DOCS) add_subdirectory(doc) endif() @@ -532,6 +495,7 @@ install(FILES ${eCAL_config} ${eCAL_config_version} install(FILES cmake/helper_functions/ecal_add_functions.cmake + cmake/helper_functions/ecal_compiler_warnings.cmake cmake/helper_functions/ecal_helper_functions.cmake cmake/helper_functions/ecal_install_functions.cmake DESTINATION ${${PROJECT_NAME}_install_cmake_dir}/helper_functions @@ -565,15 +529,14 @@ message(STATUS "HAS_CURL : ${HAS_CURL}") message(STATUS "HAS_CAPNPROTO : ${HAS_CAPNPROTO}") message(STATUS "HAS_FLATBUFFERS : ${HAS_FLATBUFFERS}") message(STATUS "HAS_FTXUI : ${HAS_FTXUI}") +message(STATUS "BUILD_SHARED_LIBS : ${BUILD_SHARED_LIBS}") message(STATUS "BUILD_DOCS : ${BUILD_DOCS}") message(STATUS "BUILD_APPS : ${BUILD_APPS}") message(STATUS "BUILD_SAMPLES : ${BUILD_SAMPLES}") message(STATUS "BUILD_TIME : ${BUILD_TIME}") message(STATUS "BUILD_PY_BINDING : ${BUILD_PY_BINDING}") -message(STATUS "BUILD_STANDALONE_PY_WHEEL : ${BUILD_STANDALONE_PY_WHEEL}") message(STATUS "BUILD_CSHARP_BINDING : ${BUILD_CSHARP_BINDING}") message(STATUS "BUILD_ECAL_TESTS : ${BUILD_ECAL_TESTS}") -message(STATUS "ECAL_INCLUDE_PY_SAMPLES : ${ECAL_INCLUDE_PY_SAMPLES}") message(STATUS "ECAL_INSTALL_SAMPLE_SOURCES : ${ECAL_INSTALL_SAMPLE_SOURCES}") message(STATUS "ECAL_NPCAP_SUPPORT : ${ECAL_NPCAP_SUPPORT}") message(STATUS "ECAL_THIRDPARTY_BUILD_ASIO : ${ECAL_THIRDPARTY_BUILD_ASIO}") @@ -586,7 +549,6 @@ message(STATUS "ECAL_THIRDPARTY_BUILD_HDF5 : ${ECAL_THIRDPAR message(STATUS "ECAL_THIRDPARTY_BUILD_PROTOBUF : ${ECAL_THIRDPARTY_BUILD_PROTOBUF}") message(STATUS "ECAL_THIRDPARTY_BUILD_QWT : ${ECAL_THIRDPARTY_BUILD_QWT}") message(STATUS "ECAL_THIRDPARTY_BUILD_RECYCLE : ${ECAL_THIRDPARTY_BUILD_RECYCLE}") -message(STATUS "ECAL_THIRDPARTY_BUILD_SIMPLEINI : ${ECAL_THIRDPARTY_BUILD_SIMPLEINI}") message(STATUS "ECAL_THIRDPARTY_BUILD_SPDLOG : ${ECAL_THIRDPARTY_BUILD_SPDLOG}") message(STATUS "ECAL_THIRDPARTY_BUILD_TCLAP : ${ECAL_THIRDPARTY_BUILD_TCLAP}") message(STATUS "ECAL_THIRDPARTY_BUILD_TCP_PUBSUB : ${ECAL_THIRDPARTY_BUILD_TCP_PUBSUB}") @@ -596,5 +558,4 @@ message(STATUS "ECAL_THIRDPARTY_BUILD_UDPCAP : ${ECAL_THIRDPAR message(STATUS "ECAL_THIRDPARTY_BUILD_YAML-CPP : ${ECAL_THIRDPARTY_BUILD_YAML-CPP}") message(STATUS "ECAL_LINK_HDF5_SHARED : ${ECAL_LINK_HDF5_SHARED}") message(STATUS "CPACK_PACK_WITH_INNOSETUP : ${CPACK_PACK_WITH_INNOSETUP}") - message(STATUS "--------------------------------------------------------------------------------") diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..3412e1e8c9 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,144 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "displayName": "Default", + "description": "Common settings for all presets.", + "binaryDir": "${sourceDir}/out/${presetName}/build", + "installDir": "${sourceDir}/out/${presetName}/install", + "cacheVariables": { + "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake/submodule_dependencies.cmake" + } + }, + { + "name": "release", + "hidden": true, + "description": "Single config Release build for inheriting", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "debug", + "hidden": true, + "description": "Single config Debug build for inheriting", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "relwithdebinfo", + "hidden": true, + "description": "Single config RelWithDebInfo build for inheriting", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "core", + "inherits": [ + "default", + "release" + ], + "displayName": "eCAL Core", + "description": "eCAL core library only configuration", + "cacheVariables": { + "HAS_HDF5": "OFF", + "HAS_QT": "OFF", + "HAS_CURL": "OFF", + "HAS_FTXUI": "OFF", + "BUILD_APPS": "OFF", + "BUILD_SAMPLES": "OFF", + "ECAL_CORE_CONFIGURATION": "OFF", + "ECAL_INSTALL_SAMPLE_SOURCES": "OFF", + "ECAL_THIRDPARTY_BUILD_FINEFTP": "OFF", + "ECAL_THIRDPARTY_BUILD_FTXUI": "OFF", + "ECAL_THIRDPARTY_BUILD_SPDLOG": "OFF", + "ECAL_THIRDPARTY_BUILD_TERMCOLOR": "OFF", + "ECAL_THIRDPARTY_BUILD_TINYXML2": "OFF", + "ECAL_THIRDPARTY_BUILD_CURL": "OFF", + "ECAL_THIRDPARTY_BUILD_HDF5": "OFF" + } + }, + { + "name": "python", + "inherits": "core", + "displayName": "Python Extensions", + "description": "Minimal build for Python extensions", + "cacheVariables": { + "HAS_HDF5": "ON", + "BUILD_PY_BINDING": "ON", + "BUILD_SHARED": "OFF", + "ECAL_THIRDPARTY_BUILD_HDF5": "ON" + } + }, + { + "name": "docs", + "inherits": "python", + "displayName": "Documentation", + "description": "Build documentation", + "cacheVariables": { + "BUILD_DOCS": "ON" + } + }, + { + "name": "cli", + "inherits": "core", + "displayName": "CLI Apps", + "description": "eCAL CLI applications", + "cacheVariables": { + "HAS_HDF5": "ON", + "HAS_CURL": "ON", + "HAS_FTXUI": "ON", + "BUILD_APPS": "ON", + "BUILD_SAMPLES": "ON", + "ECAL_THIRDPARTY_BUILD_FINEFTP": "ON", + "ECAL_THIRDPARTY_BUILD_FTXUI": "ON", + "ECAL_THIRDPARTY_BUILD_SPDLOG": "ON", + "ECAL_THIRDPARTY_BUILD_TERMCOLOR": "ON", + "ECAL_THIRDPARTY_BUILD_TINYXML2": "ON", + "ECAL_THIRDPARTY_BUILD_CURL": null, + "ECAL_THIRDPARTY_BUILD_HDF5": null + } + }, + { + "name": "gui", + "inherits": "cli", + "displayName": "GUI Apps", + "description": "eCAL GUI and CLI applications", + "cacheVariables": { + "HAS_QT": "ON" + } + } + ], + "buildPresets": [ + { + "name": "core", + "description": "Build core library only", + "configurePreset": "core" + }, + { + "name": "python", + "description": "Build python extensions", + "configurePreset": "python", + "targets": "ecal_python" + }, + { + "name": "docs", + "description": "Build sphinx documentation", + "configurePreset": "docs", + "targets": "documentation_sphinx" + }, + { + "name": "cli", + "description": "Build CLI apps", + "configurePreset": "cli" + }, + { + "name": "gui", + "description": "Build GUI and CLI apps", + "configurePreset": "gui" + } + ] +} diff --git a/NOTICE.md b/NOTICE.md new file mode 100644 index 0000000000..cec7a4474d --- /dev/null +++ b/NOTICE.md @@ -0,0 +1,312 @@ +# Notices for Eclipse eCAL + +This content is produced and maintained by the Eclipse eCAL project. + +* Project home: https://projects.eclipse.org/projects/automotive.ecal + +## Trademarks + +eCAL™ is a trademark of the Eclipse Foundation. + +## Copyright + +All content is the property of the respective authors or their employers. For +more information regarding authorship of content, please consult the listed +source code repository logs. + +## Declared Project Licenses + +This program and the accompanying materials are made available under the terms +of the Apache License, Version 2.0 which is available at +https://www.apache.org/licenses/LICENSE-2.0. + +SPDX-License-Identifier: Apache-2.0 + +## Source Code + +The project maintains the following source code repositories: + +* https://github.com/eclipse-ecal/ecal +* https://github.com/eclipse-ecal/ecal-algorithm-samples +* https://github.com/eclipse-ecal/ecal-camera-samples +* https://github.com/eclipse-ecal/ecal-carla-bridge +* https://github.com/eclipse-ecal/ecal-core +* https://github.com/eclipse-ecal/ecal-foxglove-bridge +* https://github.com/eclipse-ecal/ecal-gpsd-client +* https://github.com/eclipse-ecal/ecal-matlab-binding +* https://github.com/eclipse-ecal/ecal-mcap-tools +* https://github.com/eclipse-ecal/ecal-mqtt-bridge +* https://github.com/eclipse-ecal/ecal-rs +* https://github.com/eclipse-ecal/ecal-utils +* https://github.com/eclipse-ecal/ecaludp +* https://github.com/eclipse-ecal/fineftp-server +* https://github.com/eclipse-ecal/protobuf-datatypes-collection +* https://github.com/eclipse-ecal/rmw_ecal +* https://github.com/eclipse-ecal/rosidl_typesupport_protobuf +* https://github.com/eclipse-ecal/tcp_pubsub +* https://github.com/eclipse-ecal/udpcap + +## Third party Content + +The following components are developed by third parties. +They are used by Eclipse eCAL, but not associated to it in any way. + +### Components by Eclipse eCAL + +The following external components are developed and maintained by the Eclipse eCAL team. +They may have a different license than eCAL. + +ecaludp + - License: Apache 2.0 + - Project: https://github.com/eclipse-ecal/ecaludp + - Copyright: 2024, Continental + - Included in: + - Git submodule `/tirdparty/ecaludp/ecaludp` + - Binary distributions for Windows + - Binary distributions for Linux + +fineFTP Server + - License: MIT + - Project: https://github.com/eclipse-ecal/fineftp-server + - Copyright: 2020 Continental Corporation + - Included in: + - Git submodule `/tirdparty/fineftp/fineftp-server` + - Binary distributions for Windows + - Binary distributions for Linux + +tcp_pubsub + - License: MIT + - Project: https://github.com/eclipse-ecal/tcp_pubsub + - Copyright: 2021, Continental + - Included in: + - Git submodule `/tirdparty/tcp_pubsub/tcp_pubsub` + - Binary distributions for Windows + - Binary distributions for Linux + +Udpcap + - License: Apache 2.0 + - Project: https://github.com/eclipse-ecal/udpcap + - Copyright: 2022, Continental + - Included in: + - Git submodule `/tirdparty/udpcap/udpcap` + - Binary distributions for Windows + +### Thirdparty components + +The following components are developed by third parties. +They are used by Eclipse eCAL, but not associated to it in any way. + +Asio + - License: Boost 1.0 + - Project: https://think-async.com + - Copyright: 2003-2018 Christopher M. Kohlhoff + - Included in: + - Git submodule `/tirdparty/asio/asio` + - Binary distributions for Windows + - Binary distributions for Linux + +Bootstrap + - License: MIT + - Project: https://getbootstrap.com/ + - Copyright: 2011-2019 The Bootstrap Authors, 2011-2019 Twitter, Inc. + - Included in: + - Documentation + - Binary distributions for Windows + - Binary distributions for Linux + +Cap'n Proto + - License: MIT + - Project: https://capnproto.org + - Copyright: 2013-2014 Sandstorm Development Group, Inc. and contributors + - Included in: + - Binary distributions for Linux + +convert_utf + - License: Convert UTF License + - Copyright: 2001-2004 Unicode, Inc. + - Included in: + - Copy in repository: `convert_utf.cpp / .h` + - Binary distributions for Windows + - Binary distributions for Linux + +empy_helpers + - License: Apache 2.0 + - Project: https://github.com/ros2/rosidl/blob/master/rosidl_adapter/rosidl_adapter/resource/__init__.py + - Copyright: 2018 Open Source Robotics Foundation, Inc. + - Included in: + - Copy in repository: `/doc/extensions/empy_helpers/__init__.py` (modified) + +Findqwt.cmake + - License: Modified BSD 2-Clause + - Project: https://gitlab.kitware.com/cmake/community/-/wikis/contrib/modules/FindQwt + - Copyright: 2010-2013, Julien Schueller; 2018-2020, Rolf Eike Beer + - Included in: + - Copy in repository (modified): `cmake/Modules/Findqwt.cmake` + +Flaticons + - License: Creative Commons 3.0 + - Project: https://www.flaticon.com/ + - Copyright: Multiple individual authors + - Included in: + - Copy in repository: `/app/iconset/flaticon/*` + - Documentation + - Binary distributions for Windows + - Binary distributions for Linux + +Font Awesome + - License: Font Awesome Free License + - Project: https://fontawesome.com + - Copyright: Fonticons, Inc. + - Included in: + - Documentation + - Binary distributions for Windows + - Binary distributions for Linux + +Google Protobuf + - License: BSD 3-Clause + - Project: https://developers.google.com/protocol-buffers + - Copyright: 2008 Google Inc. + - Included in: + - Git submodule `/tirdparty/protobuf/protobuf` + - Binary distributions for Windows + +Google Test + - License: BSD 3-Clause + - Project: https://github.com/google/googletest + - Copyright: 2008 Google Inc. + - Included in: + - Git submodule `/tirdparty/gtest/googletest` + +HDF5 + - License: Modified BSD 3-Clause + - Project: https://www.hdfgroup.org/solutions/hdf5 + - Copyright: 1998-2006 by The Board of Trustees of the University of Illinois, 2006 by The HDF Group + - Included in: + - Git submodule `/tirdparty/hdf5/hdf5` + - Binary distributions for Windows + +libcurl + - License: MIT + - Project: https://curl.se/libcurl/ + - Copyright: 1996 - 2021, Daniel Stenberg, daniel@haxx.se, and many contributors (see the THANKS file) + - Included in: + - Git submodule `/tirdparty/curl/curl` + - Binary distributions for Windows + +modpath.iss + - License: LGPL 3.0 + - Project: http://www.legroom.net/software + - Copyright: Jared Breland + - Included in: + - Copy in repository: `/cpack/innosetup/modpath.iss` + - Binary distributions for Windows (Installer only) + +nanopb + - License: Zlib License + - Project: https://github.com/nanopb/nanopb + - Copyright: 2011 Petteri Aimonen \ + - Included in: + - Copy in repository: `ecal/ecal/core/src/serialization/nanopb/*` + - Binary distributions for Windows + - Binary distributions for Linux + +npcap + - License: Npcap License + - Project: https://nmap.org/npcap/ + - Copyright: 2013-2021 by Insecure.Com LLC + - Not included due to licensing issues. eCAL for Windows links against the npcap SDK. + +PcapPlusPlus + - License: Unlicense + - Project: https://pcapplusplus.github.io/ + - Copyright: 2021 seladb + - Included in: + - Binary distributions for Windows + +Qt + - License: LGPL 3.0 + - Project: https://www.qt.io/ + - Copyright: The Qt Company Ltd. + - Included in: + - Binary distributions for Windows + +qwt + - License: Qwt License + - Project: https://sourceforge.net/projects/qwt/ + - Copyright: Uwe Rathmann + - Included in: + - Git submodule `/tirdparty/qwt/qwt` + - Binary distributions for Windows + - Binary distributions for Linux + +recycle + - License: BSD 3-Clause + - Project: https://github.com/steinwurf/recycle + - Copyright: 2014, Steinwurf ApS + - Included in: + - Git submodule `/tirdparty/recycle/recycle` + - Binary distributions for Windows + - Binary distributions for Linux + +spdlog + - License: MIT + - Project: https://github.com/gabime/spdlog + - Copyright: 2016 Gabi Melman + - Included in: + - Git submodule `/tirdparty/spdlog/spdlog` + - Binary distributions for Windows + - Binary distributions for Linux + +Sphinx Book Theme + - License: BSD 3-Clause + - Project: https://github.com/executablebooks/sphinx-book-theme + - Copyright: 2020 Chris Holdgraf + - Included in: + - Documentation + - Binary distributions for Windows + - Binary distributions for Linux + +tclap + - License: MIT + - Project: http://tclap.sourceforge.net + - Copyright: 2003 Michael E. Smoot, 2004 Daniel Aarno, 2017 Google Inc. + - Included in: + - Git submodule `/tirdparty/tclap/tclap` + - Binary distributions for Windows + - Binary distributions for Linux + +termcolor + - License: BSD 3-Clause + - Project: https://github.com/ikalnytskyi/termcolor + - Copyright: 2013, Ihor Kalnytskyi + - Included in: + - Git submodule `/tirdparty/termcolor/termcolor` + - Binary distributions for Windows + - Binary distributions for Linux + +TinyXML-2 + - License: Zlib License + - Project: https://github.com/leethomason/tinyxml2 + - Copyright: Lee Thomason + - Included in: + - Git submodule `/tirdparty/tinyxml2/tinyxml2` + - Binary distributions for Windows + - Binary distributions for Linux + +yaml-cpp + - License: MIT + - Project: https://github.com/jbeder/yaml-cpp/ + - Copyright: 2008-2015 Jesse Beder + - Included in: + - Git submodule `/thirdparty/yaml-cpp/yaml-cpp` + - Binary distributions for Windows + - Binary distributions for Linux + +## Cryptography + +Content may contain encryption software. The country in which you are currently +may have restrictions on the import, possession, and use, and/or re-export to +another country, of encryption software. BEFORE using any encryption software, +please check the country's laws, regulations and policies concerning the import, +possession, or use, and re-export of encryption software, to see if this is +permitted. diff --git a/NOTICE.txt b/NOTICE.txt index 7a4ff1c10f..0049fc5990 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -1,140 +1 @@ -This project includes software developed by -Continental Corporation (https://www.continental-automotive.com) - -Licensed under the Apache License, Version 2.0 (the -"License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at: - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, -software distributed under the License is distributed on -an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -KIND, either express or implied. See the License for the -specific language governing permissions and limitations -under the License. - - -This project has dependencies - list with dependency name and license follows. - -1. Used Licenses (overall) - - - Apache License 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - - Boost Software License - http://www.boost.org/LICENSE_1_0.txt - - BSD 3-Clause License - https://opensource.org/licenses/BSD-3-Clause - - GNU Lesser General Public License v2.1 - https://www.gnu.org/licenses/old-licenses/lgpl-2.1.de.html - - GNU Lesser General Public License v3 - https://www.gnu.org/licenses/lgpl-3.0.de.html - - MIT License - https://opensource.org/licenses/MIT - - LGPL v3 - http://www.gnu.org/licenses/lgpl-3.0.html - - Some libraries like Google Protobuf define their own license model, see Details section - - -2. Details - -2.1 Networking / Transport - -2.1.1 ASIO - - Copyright © 2003-2018 Christopher M. Kohlhoff - - URL: https://think-async.com - - License: Boost Software License - http://www.boost.org/LICENSE_1_0.txt - -2.1.2 NPCAP - - Copyright 2013-2016 by Insecure.Com LLC - - URL: https://nmap.org/npcap/ - - License: Npcap License - https://github.com/nmap/npcap/blob/master/LICENSE - - -2.2 Serialization - -2.2.1 Google Protouf - - Copyright 2008 Google Inc. - - URL: https://developers.google.com/protocol-buffers - - License: https://github.com/google/protobuf/blob/master/LICENSE - -2.2.2 Cap'n Proto - - Copyright 2013-2014 Sandstorm Development Group, Inc. and contributors - - URL: https://capnproto.org - - License: MIT License - https://github.com/capnproto/capnproto/blob/master/LICENSE - -2.2.3 Google Flatbuffers - - Copyright 2014 Google Inc. - - URL: https://github.com/google/flatbuffers - - License: Apache License - https://github.com/google/flatbuffers/blob/master/LICENSE.txt - - -2.3 Utilities - -2.3.1 SimpleIni - - Copyright (c) 2006-2013 Brodie Thiesfield - - URL: https://github.com/brofield/simpleini - - License: MIT License - https://github.com/brofield/simpleini/blob/master/LICENCE.txt - -2.3.2 TCLAP - - Copyright (c) 2003 Michael E. Smoot - - Copyright (c) 2004 Daniel Aarno - - Copyright (c) 2017 Google Inc. - - URL: http://tclap.sourceforge.net - - License: MIT License - https://opensource.org/licenses/mit-license.php - -2.3.3 convert_utf.cpp/.h - - Copyright 2001-2004 Unicode, Inc. - -2.3.4 Spdlog - - Copyright (c) 2016 Gabi Melman - - URL: https://github.com/gabime/spdlog - - License: MIT License - https://github.com/gabime/spdlog/blob/v1.x/LICENSE - -2.3.5 Termcolor - - Copyright (c) 2013, Ihor Kalnytskyi - - URL: https://github.com/ikalnytskyi/termcolor - - License: BSD License - https://github.com/ikalnytskyi/termcolor/blob/master/LICENSE - -2.3.6 modpath.iss - - Copyright (c) Jared Breland - - URL: http://www.legroom.net/software - - License: LGPL 3 - -2.4 GUI - -2.4.1 QT - - Copyright 2019 The Qt Company - - URL: https://www1.qt.io/developers/ - - License: LGPLv3 - https://www1.qt.io/licensing (Applicaton Development only without none LGPL submodules) - -2.4.2 Flaticons - - Copyright 2013-2019 Freepik Company S.L. All rights reserved. - - URL: https://www.flaticon.com/ - - License: Creative Commons 3.0 - https://creativecommons.org/licenses/by/3.0 - -2.4.3 Qwt - - Uwe Rathmann, Josef Wilgen ( <= Qwt 0.2 ) - - URL: https://sourceforge.net/p/qwt/git/ci/develop/tree - - License: Qwt License Version 1.0, January 1, 2003 - -2.5 Testing - -2.5.1 GoogleTest - - Copyright 2008 Google Inc. - - URL: https://github.com/google/googletest - - License: BSD 3-Clause License - https://github.com/google/googletest/blob/master/LICENSE.txt - -2.5 Documentation - -2.5.1 Typo 3 Theme - - URL: https://github.com/TYPO3-Documentation/sphinx_typo3_theme - - License: MIT License - https://github.com/TYPO3-Documentation/sphinx_typo3_theme/blob/master/LICENSE - -2.5.2 Bootstrap - - Copyright 2011-2019 The Bootstrap Authors - - Copyright 2011-2019 Twitter, Inc. - - URL: https://getbootstrap.com/ - - License: MIT License - https://github.com/twbs/bootstrap/blob/master/LICENSE - -2.5.3 Font Awesome - - URL: https://fontawesome.com - - License: Font Awesome Free License - https://fontawesome.com/license/free - -2.5.4 empy_helpers - - Copyright 2018 Open Source Robotics Foundation, Inc. - - URL: https://github.com/ros2/rosidl/blob/master/rosidl_adapter/rosidl_adapter/resource/__init__.py - - License: Apache License +This file has been renamed to NOTICE.md \ No newline at end of file diff --git a/README.md b/README.md index 888904f0ad..3312924d21 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # eCAL - enhanced Communication Abstraction Layer -[![Build Windows Server 2019](https://github.com/eclipse-ecal/ecal/workflows/Build%20Windows%20Server%202019/badge.svg)](https://github.com/eclipse-ecal/ecal/actions?workflow=Build+Windows+Server+2019) [![Build Ubuntu 20.04](https://github.com/eclipse-ecal/ecal/workflows/Build%20Ubuntu%2020.04/badge.svg)](https://github.com/eclipse-ecal/ecal/actions?workflow=Build+Ubuntu+20.04) [![Build Ubuntu 22.04](https://github.com/eclipse-ecal/ecal/actions/workflows/build-ubuntu-22.yml/badge.svg)](https://github.com/eclipse-ecal/ecal/actions/workflows/build-ubuntu-22.yml) [![Build macOS](https://github.com/eclipse-ecal/ecal/actions/workflows/build-macos.yml/badge.svg)](https://github.com/eclipse-ecal/ecal/actions/workflows/build-macos.yml) +[![Windows](https://github.com/eclipse-ecal/ecal/actions/workflows/build-windows.yml/badge.svg)](https://github.com/eclipse-ecal/ecal/actions/workflows/build-windows.yml) [![Ubuntu](https://github.com/eclipse-ecal/ecal/actions/workflows/build-ubuntu.yml/badge.svg)](https://github.com/eclipse-ecal/ecal/actions/workflows/build-ubuntu.yml) [![macOS](https://github.com/eclipse-ecal/ecal/actions/workflows/build-macos.yml/badge.svg)](https://github.com/eclipse-ecal/ecal/actions/workflows/build-macos.yml) [![License](https://img.shields.io/github/license/continental/ecal.svg?style=flat)](LICENSE.txt) @@ -50,7 +50,7 @@ We provide binary installers for Windows and Ubuntu. If you need further help in ![eCAL Setup](doc/rst/getting_started/img/setup.png) -*We only support 64bit Windows 7 / 10* +*We only support 64bit Windows 10 / 11* ### Ubuntu @@ -63,7 +63,7 @@ sudo apt-get install ecal ``` This PPA will always upgrade you to the latest eCAL Release (-> Rolling Release PPA). If you intend to stay on an specific release, check out other PPAs [here](https://eclipse-ecal.github.io/ecal/getting_started/setup.html#fa-ubuntu-automatically-install-ecal-from-a-ppa). -*Ubuntu 18.04, 20.04, 22.04, 23.04, 23.10 for CPU architectures (i386), x64, armhf, arm64 are supported at the time of writing.* +*Ubuntu 18.04, 20.04, 22.04, 24.04 for CPU architectures amd64, armhf, arm64 are supported at the time of writing. Non-LTS versions of Ubuntu are usually supported, too.* ## Example diff --git a/app/app_pb/CMakeLists.txt b/app/app_pb/CMakeLists.txt index edd036188f..0b2dc7e8e4 100644 --- a/app/app_pb/CMakeLists.txt +++ b/app/app_pb/CMakeLists.txt @@ -68,15 +68,9 @@ target_compile_options(${PROJECT_NAME} set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(${PROJECT_NAME} protobuf::libprotobuf) +target_link_libraries(${PROJECT_NAME} PUBLIC protobuf::libprotobuf) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) ecal_install_library(${PROJECT_NAME}) -if(BUILD_PY_BINDING) - protobuf_generate_python_ext(python_sources ${PYTHON_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src ${ProtoFiles}) - target_sources(${PROJECT_NAME} PRIVATE ${python_sources}) - set_source_files_properties(${python_sources} PROPERTIES HEADER_FILE_ONLY TRUE) -endif() - set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER app/app_pb) diff --git a/app/meas_cutter/CMakeLists.txt b/app/meas_cutter/CMakeLists.txt index 4209e6c380..442c3087a5 100644 --- a/app/meas_cutter/CMakeLists.txt +++ b/app/meas_cutter/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2024 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -22,13 +22,8 @@ find_package(Threads REQUIRED) find_package(tclap REQUIRED) find_package(yaml-cpp REQUIRED) -#compatibility with yaml-cpp < 0.8.0 -if (NOT TARGET yaml-cpp::yaml-cpp AND TARGET yaml-cpp) - # ALIASing a imported non-global library requires CMake 3.18 so we do this - add_library(yaml-cpp::yaml-cpp INTERFACE IMPORTED) - target_link_libraries(yaml-cpp::yaml-cpp INTERFACE yaml-cpp) -endif() - +include(${ECAL_PROJECT_ROOT}/thirdparty/yaml-cpp/compatibility-yaml-cpp.cmake) +yaml_cpp_create_compatibility_targets() set(meas_cutter_src src/main.cpp @@ -57,11 +52,13 @@ ecal_add_app_console(${PROJECT_NAME} ${meas_cutter_src}) target_include_directories(${PROJECT_NAME} PRIVATE $) -target_link_libraries(${PROJECT_NAME} yaml-cpp::yaml-cpp - tclap::tclap - eCAL::ecal-utils - eCAL::measurement_hdf5 - Threads::Threads) +target_link_libraries(${PROJECT_NAME} PRIVATE + yaml-cpp::yaml-cpp + tclap::tclap + eCAL::ecal-utils + eCAL::hdf5 + Threads::Threads +) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) diff --git a/app/meas_cutter/src/config_file_parser.h b/app/meas_cutter/src/config_file_parser.h index 4efa8e3583..e545b80c86 100644 --- a/app/meas_cutter/src/config_file_parser.h +++ b/app/meas_cutter/src/config_file_parser.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ #include #include -#define YAML_CPP_STATIC_DEFINE +//#define YAML_CPP_STATIC_DEFINE // set by CMake #include #include "utils.h" diff --git a/app/meas_cutter/src/measurement_exporter.cpp b/app/meas_cutter/src/measurement_exporter.cpp index 909be8bbf0..115c454cb2 100644 --- a/app/meas_cutter/src/measurement_exporter.cpp +++ b/app/meas_cutter/src/measurement_exporter.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,9 @@ */ #include "measurement_exporter.h" -#include MeasurementExporter::MeasurementExporter(): - _writer(std::make_unique()) + _writer(std::make_unique()) { } @@ -29,7 +28,7 @@ void MeasurementExporter::setPath(const std::string& path, const std::string& ba { _root_output_path = EcalUtils::Filesystem::CleanPath(path); _output_path = EcalUtils::Filesystem::CleanPath(_root_output_path + EcalUtils::Filesystem::NativeSeparator(EcalUtils::Filesystem::OsStyle::Current) + eCALMeasCutterUtils::kDefaultFolderOutput, EcalUtils::Filesystem::OsStyle::Current); - if (!_writer->Open(_output_path)) + if (!_writer->Open(_output_path, eCAL::eh5::v2::eAccessType::CREATE)) { throw ExporterException("Unable to create HDF5 protobuf output path " + path + "."); } @@ -54,15 +53,18 @@ MeasurementExporter::~MeasurementExporter() void MeasurementExporter::createChannel(const std::string& channel_name, const eCALMeasCutterUtils::ChannelInfo& channel_info) { _current_channel_name = channel_name; + eCAL::experimental::measurement::base::DataTypeInformation data_type_info; if (channel_info.format == eCALMeasCutterUtils::SerializationFormat::PROTOBUF) { - _writer->SetChannelType(channel_name, "proto:" + channel_info.type); + data_type_info.encoding = "proto"; } else { - _writer->SetChannelType(channel_name, channel_info.type); + data_type_info.encoding = ""; } - _writer->SetChannelDescription(channel_name, channel_info.description); + data_type_info.name = channel_info.type; + data_type_info.descriptor = channel_info.description; + _writer->SetChannelDataTypeInformation(channel_name, data_type_info); } void MeasurementExporter::setData(eCALMeasCutterUtils::Timestamp timestamp, const eCALMeasCutterUtils::MetaData& meta_data, const std::string& payload) @@ -73,10 +75,10 @@ void MeasurementExporter::setData(eCALMeasCutterUtils::Timestamp timestamp, cons const auto sender_timestamp = (iter != meta_data.end()) ? iter->second.sender_timestamp : static_cast(0); iter = meta_data.find(eCALMeasCutterUtils::MetaDatumKey::SENDER_ID); - const auto sender_id = (iter != meta_data.end()) ? iter->second.sender_id : static_cast(0); + const auto sender_id = (iter != meta_data.end()) ? iter->second.sender_id : 0; iter = meta_data.find(eCALMeasCutterUtils::MetaDatumKey::SENDER_CLOCK); - const auto sender_clock = (iter != meta_data.end()) ? iter->second.sender_clock : static_cast(0); + const auto sender_clock = (iter != meta_data.end()) ? iter->second.sender_clock : 0; if (!_writer->AddEntryToFile(payload.data(), payload.size(), sender_timestamp, timestamp, _current_channel_name, sender_id, sender_clock)) { diff --git a/app/meas_cutter/src/measurement_exporter.h b/app/meas_cutter/src/measurement_exporter.h index 3d8c51334d..eea8290381 100644 --- a/app/meas_cutter/src/measurement_exporter.h +++ b/app/meas_cutter/src/measurement_exporter.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,11 +18,14 @@ */ #pragma once + #include -#include #include +#include +#include +#include -#include +#include #include #include "utils.h" @@ -43,7 +46,7 @@ class MeasurementExporter std::string getRootOutputPath() const; private: - std::unique_ptr _writer; + std::unique_ptr _writer; std::string _current_channel_name; std::string _output_path; std::string _root_output_path; diff --git a/app/meas_cutter/src/measurement_importer.cpp b/app/meas_cutter/src/measurement_importer.cpp index 717acd3649..62ab0eb102 100644 --- a/app/meas_cutter/src/measurement_importer.cpp +++ b/app/meas_cutter/src/measurement_importer.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,10 +18,10 @@ */ #include "measurement_importer.h" -#include +#include MeasurementImporter::MeasurementImporter() : - _reader(std::make_unique()), + _reader(std::make_unique()), _current_opened_channel_data() { } @@ -67,17 +67,17 @@ void MeasurementImporter::openChannel(const std::string& channel_name) _current_opened_channel_data._timestamps.clear(); _current_opened_channel_data._timestamp_entry_info_map.clear(); - if (isProtoChannel(_reader->GetChannelType(channel_name))) + auto channel_information = _reader->GetChannelDataTypeInformation(channel_name); + if (isProtoChannel(channel_information)) { _current_opened_channel_data._channel_info.format = eCALMeasCutterUtils::SerializationFormat::PROTOBUF; - _current_opened_channel_data._channel_info.type = _reader->GetChannelType(channel_name).substr(6); // remove "proto:" from type string } else { _current_opened_channel_data._channel_info.format = eCALMeasCutterUtils::SerializationFormat::UNKNOWN; - _current_opened_channel_data._channel_info.type = _reader->GetChannelType(channel_name); } - _current_opened_channel_data._channel_info.description = _reader->GetChannelDescription(channel_name); + _current_opened_channel_data._channel_info.type = channel_information.name; + _current_opened_channel_data._channel_info.description = channel_information.descriptor; _current_opened_channel_data._channel_info.name = channel_name; eCAL::experimental::measurement::base::EntryInfoSet entry_info_set; @@ -177,10 +177,9 @@ bool MeasurementImporter::isEcalMeasFile(const std::string& path) return false; } -bool MeasurementImporter::isProtoChannel(const std::string& channel_type) +bool MeasurementImporter::isProtoChannel(const eCAL::experimental::measurement::base::DataTypeInformation& channel_info) { - std::string space = channel_type.substr(0, channel_type.find_first_of(':')); - return (space.compare("proto") == 0); + return (channel_info.encoding == "proto"); } std::string MeasurementImporter::getLoadedPath() diff --git a/app/meas_cutter/src/measurement_importer.h b/app/meas_cutter/src/measurement_importer.h index 6f1c348f87..bd40390780 100644 --- a/app/meas_cutter/src/measurement_importer.h +++ b/app/meas_cutter/src/measurement_importer.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,16 @@ */ #pragma once -#include #include -#include #include -#include +#include +#include +#include +#include +#include #include -#include +#include #include "utils.h" @@ -52,8 +54,8 @@ class MeasurementImporter private: bool isEcalMeasFile(const std::string& path); - bool isProtoChannel(const std::string& channel_type); - std::unique_ptr _reader; + bool isProtoChannel(const eCAL::experimental::measurement::base::DataTypeInformation& channel_info); + std::unique_ptr _reader; eCALMeasCutterUtils::ChannelData _current_opened_channel_data; std::string _loaded_path; eCALMeasCutterUtils::ChannelNameSet _channel_names; diff --git a/app/meas_cutter/src/utils.h b/app/meas_cutter/src/utils.h index 9d40dee26f..0523391c10 100644 --- a/app/meas_cutter/src/utils.h +++ b/app/meas_cutter/src/utils.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include #include -#define YAML_CPP_STATIC_DEFINE +//#define YAML_CPP_STATIC_DEFINE // set by CMake #include "yaml-cpp/yaml.h" #include @@ -312,10 +312,10 @@ namespace eCALMeasCutterUtils { Timestamp receiver_timestamp; Timestamp sender_timestamp; - uint64_t sender_id; - uint64_t sender_clock; + int64_t sender_id; + int64_t sender_clock; - std::array __union_size; + std::array __union_size; }; typedef std::unordered_map MetaData; diff --git a/app/mon/mon_cli/CMakeLists.txt b/app/mon/mon_cli/CMakeLists.txt index aad13afc55..f4923bdf0e 100644 --- a/app/mon/mon_cli/CMakeLists.txt +++ b/app/mon/mon_cli/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -41,12 +41,12 @@ target_compile_definitions(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries(${PROJECT_NAME} - protobuf::libprotobuf +target_link_libraries(${PROJECT_NAME} PRIVATE tclap::tclap - eCAL::core + eCAL::protobuf_core + eCAL::string_core eCAL::core_pb) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) ecal_install_app(${PROJECT_NAME}) diff --git a/app/mon/mon_cli/src/ecal_mon_cli.cpp b/app/mon/mon_cli/src/ecal_mon_cli.cpp index 0988ab8640..7534a7e463 100644 --- a/app/mon/mon_cli/src/ecal_mon_cli.cpp +++ b/app/mon/mon_cli/src/ecal_mon_cli.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -209,10 +209,12 @@ int main(int argc, char** argv) } // initialize eCAL API - eCAL::Initialize(0, nullptr, "eCALMon CLI", eCAL::Init::All); + auto config = eCAL::Init::Configuration(); + config.logging.receiver.enable = true; + eCAL::Initialize(config, "eCALMon CLI", eCAL::Init::All); // set process state - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); switch (cmd_option) { @@ -332,7 +334,7 @@ void ProcEcho(const std::string& topic_name, int msg_count) eCAL::string::CSubscriber sub(topic_name); std::atomic cnt(msg_count); auto msg_cb = [&cnt](const std::string& msg_) { if (cnt != 0) { std::cout << msg_ << std::endl; if (cnt > 0) cnt--; } }; - sub.AddReceiveCallback(std::bind(msg_cb, std::placeholders::_2)); + sub.SetReceiveCallback(std::bind(msg_cb, std::placeholders::_2)); while(eCAL::Ok() && (cnt != 0)) { @@ -351,20 +353,11 @@ void ProcProto(const std::string& topic_name, int msg_count) // sleep 1000 ms std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - // get topic type - eCAL::SDataTypeInformation topic_info; - eCAL::Util::GetTopicDataTypeInformation(topic_name, topic_info); - if(topic_info.name.empty()) - { - std::cout << "could not get type name for topic " << topic_name << std::endl; - return; - } - // create dynamic subscribers for receiving and decoding messages and assign callback eCAL::protobuf::CDynamicSubscriber sub(topic_name); std::atomic cnt(msg_count); - auto msg_cb = [&cnt](const google::protobuf::Message& msg_) { if (cnt != 0) { std::cout << msg_.DebugString() << std::endl; if (cnt > 0) cnt--; } }; - sub.AddReceiveCallback(std::bind(msg_cb, std::placeholders::_2)); + auto msg_cb = [&cnt](const std::shared_ptr& msg_) { if (cnt != 0) { std::cout << msg_->DebugString() << std::endl; if (cnt > 0) cnt--; } }; + sub.SetReceiveCallback(std::bind(msg_cb, std::placeholders::_2)); // enter main loop while(eCAL::Ok() && (cnt != 0)) @@ -377,9 +370,9 @@ void ProcProto(const std::string& topic_name, int msg_count) ////////////////////////////////////////// // find topics by type ////////////////////////////////////////// -void ProcFind(const std::string& topic_type) +void ProcFind(const std::string& topic_type_name) { - std::cout << "display all topics with type " << topic_type << std::endl << std::endl;; + std::cout << "display all topics with type " << topic_type_name << std::endl << std::endl;; // monitoring instance to store complete snapshot eCAL::pb::Monitoring monitoring; @@ -400,15 +393,16 @@ void ProcFind(const std::string& topic_type) for(const auto& topic : monitoring.topics()) { // check topic name - if(topic.ttype() != topic_type) continue; + if(topic.tdatatype().name() != topic_type_name) continue; // print topic details - std::cout << "tname : " << topic.tname() << std::endl; // topic name - std::cout << "ttype : " << topic.ttype() << std::endl; // topic type - std::cout << "direction : " << topic.direction() << std::endl; // direction (publisher, subscriber) - std::cout << "hname : " << topic.hname() << std::endl; // host name - std::cout << "pid : " << topic.pid() << std::endl; // process id - std::cout << "tid : " << topic.tid() << std::endl; // topic id + std::cout << "tname : " << topic.tname() << std::endl; // topic name + std::cout << "ttype name : " << topic.tdatatype().name() << std::endl; // topic type name + std::cout << "ttype enc. : " << topic.tdatatype().encoding() << std::endl; // topic type encoding + std::cout << "direction : " << topic.direction() << std::endl; // direction (publisher, subscriber) + std::cout << "hname : " << topic.hname() << std::endl; // host name + std::cout << "pid : " << topic.pid() << std::endl; // process id + std::cout << "tid : " << topic.tid() << std::endl; // topic id std::cout << std::endl; } @@ -481,15 +475,16 @@ void ProcInfo(const std::string& topic_name) if(topic.tname() != topic_name) continue; // print topic details - std::cout << "tname : " << topic.tname() << std::endl; // topic name - std::cout << "ttype : " << topic.ttype() << std::endl; // topic type - std::cout << "direction : " << topic.direction() << std::endl; // direction (publisher, subscriber) - std::cout << "hname : " << topic.hname() << std::endl; // host name - std::cout << "pid : " << topic.pid() << std::endl; // process id - std::cout << "tid : " << topic.tid() << std::endl; // topic id - std::cout << "tsize : " << topic.tsize() << std::endl; // topic size - std::cout << "dclock : " << topic.dclock() << std::endl; // data clock (send / receive action) - std::cout << "dfreq : " << topic.dfreq()/1000.0 << std::endl; // data frequency (send / receive samples per second * 1000) + std::cout << "tname : " << topic.tname() << std::endl; // topic name + std::cout << "ttype name : " << topic.tdatatype().name() << std::endl; // topic type name + std::cout << "ttype enc. : " << topic.tdatatype().encoding() << std::endl; // topic type encoding + std::cout << "direction : " << topic.direction() << std::endl; // direction (publisher, subscriber) + std::cout << "hname : " << topic.hname() << std::endl; // host name + std::cout << "pid : " << topic.pid() << std::endl; // process id + std::cout << "tid : " << topic.tid() << std::endl; // topic id + std::cout << "tsize : " << topic.tsize() << std::endl; // topic size + std::cout << "dclock : " << topic.dclock() << std::endl; // data clock (send / receive action) + std::cout << "dfreq : " << topic.dfreq()/1000.0 << std::endl; // data frequency (send / receive samples per second * 1000) std::cout << std::endl; } @@ -524,15 +519,16 @@ void ProcList() for(const auto& topic : monitoring.topics()) { // print topic details - std::cout << "tname : " << topic.tname() << std::endl; // topic name - std::cout << "ttype : " << topic.ttype() << std::endl; // topic type - std::cout << "direction : " << topic.direction() << std::endl; // direction (publisher, subscriber) - std::cout << "hname : " << topic.hname() << std::endl; // host name - std::cout << "pid : " << topic.pid() << std::endl; // process id - std::cout << "tid : " << topic.tid() << std::endl; // topic id - std::cout << "tsize : " << topic.tsize() << std::endl; // topic size - std::cout << "dclock : " << topic.dclock() << std::endl; // data clock (send / receive action) - std::cout << "dfreq : " << topic.dfreq()/1000.0 << std::endl; // data frequency (send / receive samples per second * 1000) + std::cout << "tname : " << topic.tname() << std::endl; // topic name + std::cout << "ttype name : " << topic.tdatatype().name() << std::endl; // topic type name + std::cout << "ttype enc. : " << topic.tdatatype().encoding() << std::endl; // topic type encoding + std::cout << "direction : " << topic.direction() << std::endl; // direction (publisher, subscriber) + std::cout << "hname : " << topic.hname() << std::endl; // host name + std::cout << "pid : " << topic.pid() << std::endl; // process id + std::cout << "tid : " << topic.tid() << std::endl; // topic id + std::cout << "tsize : " << topic.tsize() << std::endl; // topic size + std::cout << "dclock : " << topic.dclock() << std::endl; // data clock (send / receive action) + std::cout << "dfreq : " << topic.dfreq()/1000.0 << std::endl; // data frequency (send / receive samples per second * 1000) std::cout << std::endl; } @@ -567,11 +563,11 @@ void ProcPub(const std::string& topic_name, const std::string& data) } ////////////////////////////////////////// -// print topic type +// print topic type name ////////////////////////////////////////// void ProcType(const std::string& topic_name) { - std::cout << "print type of topic " << topic_name << std::endl << std::endl;; + std::cout << "print type name of topic " << topic_name << std::endl << std::endl;; // monitoring instance to store complete snapshot eCAL::pb::Monitoring monitoring; @@ -592,11 +588,11 @@ void ProcType(const std::string& topic_name) // check topic name if(topic.tname() != topic_name) continue; - std::string ttype = topic.ttype(); - if(ttype.empty()) ttype = "unknown"; + std::string ttype_name = topic.tdatatype().name(); + if(ttype_name.empty()) ttype_name = "\"\""; // print topic type - std::cout << ttype << " (" << topic.hname() << ":" << topic.direction() << ")" << std::endl; + std::cout << ttype_name << " (" << topic.hname() << ":" << topic.direction() << ")" << std::endl; } } @@ -624,9 +620,12 @@ void ProcDesc(const std::string& topic_name_) for(const auto& topic : monitoring.topics()) { // check topic name - if((topic.tname() != topic_name_) || topic.ttype().empty()) continue; + if(topic.tname() != topic_name_) continue; + + std::string ttype_desc = topic.tdatatype().desc(); + if (ttype_desc.empty()) ttype_desc = "\"\""; // print topic description - std::cout << topic.tdesc() << " (" << topic.hname() << ":" << topic.direction() << ")" << std::endl; + std::cout << ttype_desc << " (" << topic.hname() << ":" << topic.direction() << ")" << std::endl; } } diff --git a/app/mon/mon_gui/CMakeLists.txt b/app/mon/mon_gui/CMakeLists.txt index ba84cabce4..4a2523ad00 100644 --- a/app/mon/mon_gui/CMakeLists.txt +++ b/app/mon/mon_gui/CMakeLists.txt @@ -102,7 +102,6 @@ set(source_files src/widgets/models/process_tree_item.h src/widgets/models/process_tree_model.cpp src/widgets/models/process_tree_model.h - src/widgets/models/service_tree_item.cpp src/widgets/models/service_tree_item.h src/widgets/models/service_tree_model.cpp src/widgets/models/service_tree_model.h @@ -196,7 +195,7 @@ ecal_add_app_qt(${PROJECT_NAME} ${autogen_ui} ) -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE protobuf::libprotobuf eCAL::core eCAL::core_pb @@ -210,7 +209,7 @@ target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) if(ECAL_NPCAP_SUPPORT) add_definitions(-DECAL_NPCAP_SUPPORT) - target_link_libraries(${PROJECT_NAME} + target_link_libraries(${PROJECT_NAME} PRIVATE udpcap::udpcap ) endif(ECAL_NPCAP_SUPPORT) diff --git a/app/mon/mon_gui/src/ecalmon.cpp b/app/mon/mon_gui/src/ecalmon.cpp index 2abed6fd10..5b88861e7c 100644 --- a/app/mon/mon_gui/src/ecalmon.cpp +++ b/app/mon/mon_gui/src/ecalmon.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ #include "ecalmon.h" #include "ecal/ecal.h" -#include +#include #include "widgets/about_dialog/about_dialog.h" #include "widgets/license_dialog/license_dialog.h" @@ -71,9 +71,10 @@ Ecalmon::Ecalmon(QWidget *parent) , monitor_error_counter_(0) { // Just make sure that eCAL is initialized - eCAL::Initialize(0, nullptr, "eCALMon", eCAL::Init::Default | eCAL::Init::Monitoring); - eCAL::Monitoring::SetFilterState(false); - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + auto config = eCAL::Init::Configuration(); + config.logging.receiver.enable = true; + eCAL::Initialize(config, "eCALMon", eCAL::Init::Default | eCAL::Init::Monitoring); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); ui_.setupUi(this); @@ -102,21 +103,21 @@ Ecalmon::Ecalmon(QWidget *parent) if (multicast_ttl <= 0) { - network_mode_widget_->setToolTip("ERROR: Network enabled but TTL is " + QString::number(multicast_ttl) + ". Change via ecal.ini"); + network_mode_widget_->setToolTip("ERROR: Network enabled but TTL is " + QString::number(multicast_ttl) + ". Change via ecal.yaml"); network_mode_widget_->setStyleSheet("background-color: rgb(255, 128, 128); color: black"); network_mode_warning_icon_->setVisible(true); } else { network_mode_widget_->setStyleSheet("background-color: rgb(80, 255, 120); color: black"); - network_mode_widget_->setToolTip("Change via ecal.ini"); + network_mode_widget_->setToolTip("Change via ecal.yaml"); } } else { network_mode_label_->setText("Network mode: Local"); network_mode_widget_->setStyleSheet("background-color: rgb(44, 148, 255); color: black"); - network_mode_widget_->setToolTip("Change via ecal.ini"); + network_mode_widget_->setToolTip("Change via ecal.yaml"); } error_label_ = new QLabel(this); @@ -371,7 +372,7 @@ void Ecalmon::updateMonitor() #ifndef NDEBUG qDebug().nospace() << "[" << metaObject()->className() << "Error getting Monitoring Information"; #endif // NDEBUG - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_error, "Error getting eCAL Monitoring information"); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_error, "Error getting eCAL Monitoring information"); } } diff --git a/app/mon/mon_gui/src/plugin/plugin_manager.cpp b/app/mon/mon_gui/src/plugin/plugin_manager.cpp index 0e5b065ff1..c89b212ba7 100644 --- a/app/mon/mon_gui/src/plugin/plugin_manager.cpp +++ b/app/mon/mon_gui/src/plugin/plugin_manager.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include std::unique_ptr PluginManager::instance_; @@ -135,14 +135,14 @@ void PluginManager::AddFoundPlugins(const QVector& library_paths) plugins_.insert(iid, ActivePlugin{ plugin, false }); else { if (plugin_iter->wrapper.getPluginData().path != file_path) - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_warning, + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_warning, "Ambiguous plugin iid " + iid.toStdString() + " of " + meta_data.name.toStdString() + " " + meta_data.version.toStdString() + ". Plugin " + file_path.toStdString() + " was not loaded."); } } catch (const std::runtime_error &e) { - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_warning, + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_warning, std::string(e.what()) + " Plugin " + file_path.toStdString() + " was not loaded."); } } diff --git a/app/mon/mon_gui/src/plugin/plugin_wrapper.cpp b/app/mon/mon_gui/src/plugin/plugin_wrapper.cpp index 2355e856f0..5d7281142d 100644 --- a/app/mon/mon_gui/src/plugin/plugin_wrapper.cpp +++ b/app/mon/mon_gui/src/plugin/plugin_wrapper.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ #include -#include +#include QPair splitTopicType(const QString& topic_type) { @@ -104,25 +104,25 @@ bool PluginWrapper::load() eCAL::mon::PluginInterface* plugin = qobject_cast(instance); if (plugin) { - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_info, "Plugin " + plugin_data_.meta_data.name.toStdString() + " " + plugin_data_.meta_data.version.toStdString() + " has been loaded."); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_info, "Plugin " + plugin_data_.meta_data.name.toStdString() + " " + plugin_data_.meta_data.version.toStdString() + " has been loaded."); instance_ = std::shared_ptr(plugin, [this](eCAL::mon::PluginInterface* p) { - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_info, "Plugin " + plugin_data_.meta_data.name.toStdString() + " " + plugin_data_.meta_data.version.toStdString() + " has been unloaded."); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_info, "Plugin " + plugin_data_.meta_data.name.toStdString() + " " + plugin_data_.meta_data.version.toStdString() + " has been unloaded."); delete dynamic_cast(p); }); return true; } else { - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_warning, "Plugin " + plugin_data_.path.toStdString() + " is not suitable for eCAL Monitor"); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_warning, "Plugin " + plugin_data_.path.toStdString() + " is not suitable for eCAL Monitor"); loader.unload(); } } else { - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_warning, "Unable to load plugin " + plugin_data_.path.toStdString() + "."); - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_warning, loader.errorString().toStdString()); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_warning, "Unable to load plugin " + plugin_data_.path.toStdString() + "."); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_warning, loader.errorString().toStdString()); } } else diff --git a/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.cpp b/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.cpp index b3d77fb472..c0e5b8c508 100644 --- a/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.cpp +++ b/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.cpp @@ -20,9 +20,10 @@ #include "about_dialog.h" #include "ecalmon_globals.h" -#include +#include #include +#include AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) @@ -30,6 +31,12 @@ AboutDialog::AboutDialog(QWidget *parent) ui_.setupUi(this); ui_.version_label->setText("Version: " + QString(EcalmonGlobals::VERSION_STRING)); ui_.ecalversion_label->setText("eCAL " + QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + + ui_.ecal_runtime_version_string_label->setText(QString::fromStdString(eCAL::GetVersionString()) + " (" + QString::fromStdString(eCAL::GetVersionDateString()) + ")"); + ui_.ecal_compiletime_versin_string_label->setText(QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + ui_.qt_runtime_version_string_label->setText(QString(qVersion())); + ui_.qt_compiletime_version_string_label->setText(QString(QT_VERSION_STR)); + connect(ui_.button_box->button(QDialogButtonBox::StandardButton::Ok), SIGNAL(clicked()), this, SLOT(close())); } diff --git a/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.ui b/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.ui index 8fd1430cb4..bdcb82fbba 100644 --- a/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.ui +++ b/app/mon/mon_gui/src/widgets/about_dialog/about_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 326 - 209 + 304 + 312 @@ -62,7 +62,6 @@ Advanced Engineering Department Developed by Florian Reimold Based on work by Rex Schilasky, Ileana Zepa - @@ -73,6 +72,68 @@ Based on work by Rex Schilasky, Ileana Zepa + + + + + + + Qt runtime version: + + + + + + + qt-runtime-version + + + + + + + eCAL runtime version: + + + + + + + ecal-runtime-version + + + + + + + eCAL compile-time version: + + + + + + + ecal-compiletime-version + + + + + + + Qt compile-time version: + + + + + + + qt-compiletime-version + + + + + + diff --git a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/ecalmon_tree_widget.cpp b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/ecalmon_tree_widget.cpp index 1de5585efb..97f4173e2d 100644 --- a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/ecalmon_tree_widget.cpp +++ b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/ecalmon_tree_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -508,7 +508,7 @@ void EcalmonTreeWidget::loadGuiSettings(const QString& group) QVector group_by_columns; int auto_expand = 0; - for (auto column_variant : settings.value("group_by_columns").toList()) + for (const auto& column_variant : settings.value("group_by_columns").toList()) { int column = column_variant.toInt(); if ((column >= 0) && (column < group_tree_model_->columnCount())) diff --git a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/host_widget.cpp b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/host_widget.cpp index 604eb3fa98..fb01960bd7 100644 --- a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/host_widget.cpp +++ b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/host_widget.cpp @@ -92,11 +92,6 @@ void HostWidget::autoSizeColumns() example_process_pb->set_pname(""); example_process_pb->set_uname("CameraSensorMapFusionCAF___"); example_process_pb->set_pparam(""); - example_process_pb->set_pmemory(99999999999); - example_process_pb->set_pcpu(1000); - example_process_pb->set_usrptime(999999.9999f); - example_process_pb->set_datawrite(99999999999); - example_process_pb->set_dataread(99999999999); HostTreeItem* example_host_item = new HostTreeItem("CARPC00____"); example_host_item->update(example_monitoring_pb); diff --git a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/process_widget.cpp b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/process_widget.cpp index db59d3b994..1530e27834 100644 --- a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/process_widget.cpp +++ b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/process_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,11 +64,11 @@ ProcessWidget::ProcessWidget(QWidget *parent) host.name = "Host"; preconfigured_group_by_settings.push_back(host); - EcalmonTreeWidget::GroupSetting host_group; - host_group.group_by_columns = { (int)ProcessTreeModel::Columns::HOST_GROUP_NAME }; - host_group.auto_expand = 0; - host_group.name = "Host Group"; - preconfigured_group_by_settings.push_back(host_group); + EcalmonTreeWidget::GroupSetting shm_transport_domain; + shm_transport_domain.group_by_columns = { (int)ProcessTreeModel::Columns::SHM_TRANSPORT_DOMAIN }; + shm_transport_domain.auto_expand = 0; + shm_transport_domain.name = "SHM Transport Domain"; + preconfigured_group_by_settings.push_back(shm_transport_domain); setGroupSettings(preconfigured_group_by_settings, group_by_enabled_columns); @@ -86,10 +86,6 @@ ProcessWidget::ProcessWidget(QWidget *parent) (int)ProcessTreeModel::Columns::STATE, (int)ProcessTreeModel::Columns::INFO, (int)ProcessTreeModel::Columns::HEARTBEAT, - (int)ProcessTreeModel::Columns::MEMORY, - (int)ProcessTreeModel::Columns::CPU_PERCENTAGE, - (int)ProcessTreeModel::Columns::DATAWRITE, - (int)ProcessTreeModel::Columns::DATAREAD, (int)ProcessTreeModel::Columns::ECAL_RUNTIME_VERSION, }; setVisibleColumns(default_visible_columns); @@ -118,11 +114,6 @@ void ProcessWidget::autoSizeColumns() example_process_pb.set_pname(""); example_process_pb.set_uname("eCALProcessUnitNameABCDE___"); example_process_pb.set_pparam(""); - example_process_pb.set_pmemory(99999999999); - example_process_pb.set_pcpu(1000); - example_process_pb.set_usrptime(999999.9999f); - example_process_pb.set_datawrite(99999999999); - example_process_pb.set_dataread(99999999999); example_process_pb.mutable_state()->set_severity(eCAL::pb::eProcessSeverity::proc_sev_warning); example_process_pb.mutable_state()->set_severity_level(eCAL::pb::eProcessSeverityLevel::proc_sev_level5); @@ -143,15 +134,11 @@ void ProcessWidget::autoSizeColumns() (int)ProcessTreeModel::Columns::PROCESS_NAME, (int)ProcessTreeModel::Columns::STATE, (int)ProcessTreeModel::Columns::HEARTBEAT, - (int)ProcessTreeModel::Columns::MEMORY, - (int)ProcessTreeModel::Columns::CPU_PERCENTAGE, - (int)ProcessTreeModel::Columns::USER_TIME, - (int)ProcessTreeModel::Columns::DATAWRITE, - (int)ProcessTreeModel::Columns::DATAREAD, (int)ProcessTreeModel::Columns::TIMESYNC_STATE, (int)ProcessTreeModel::Columns::TIMESYNC_MOD_NAME, (int)ProcessTreeModel::Columns::COMPONENT_INIT_INFO, (int)ProcessTreeModel::Columns::ECAL_RUNTIME_VERSION, + (int)ProcessTreeModel::Columns::CONFIG_FILE_PATH, }; for (int column : columns_to_resize) diff --git a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/service_widget.cpp b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/service_widget.cpp index bb2d7d9839..7b4ca5e4f4 100644 --- a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/service_widget.cpp +++ b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/service_widget.cpp @@ -49,6 +49,7 @@ ServiceWidget::ServiceWidget(QWidget *parent) (int)ServiceTreeModel::Columns::UNIT_NAME, (int)ServiceTreeModel::Columns::PID, (int)ServiceTreeModel::Columns::SERVICE_NAME, + (int)ServiceTreeModel::Columns::SERVICE_TYPE, (int)ServiceTreeModel::Columns::TCP_PORT, (int)ServiceTreeModel::Columns::METHOD_NAME, (int)ServiceTreeModel::Columns::METHOD_REQUEST_TYPE, @@ -79,6 +80,7 @@ ServiceWidget::ServiceWidget(QWidget *parent) { (int)ServiceTreeModel::Columns::UNIT_NAME, (int)ServiceTreeModel::Columns::SERVICE_NAME, + (int)ServiceTreeModel::Columns::SERVICE_TYPE, (int)ServiceTreeModel::Columns::HOST_NAME, (int)ServiceTreeModel::Columns::PID, (int)ServiceTreeModel::Columns::METHOD_NAME, @@ -122,7 +124,7 @@ void ServiceWidget::autoSizeColumns() method->set_resp_type("ShutdownProcessNameResponse____"); method->set_call_count(999999); - ServiceTreeItem* example_topic_item = new ServiceTreeItem(example_service_pb, *method); + auto* example_topic_item = new ServiceTreeItem(example_service_pb, *method); GroupTreeItem* example_group_item = new GroupTreeItem("__ / eCALRPCService____", "", "", QVariant(), ""); service_tree_model_->insertItem(example_topic_item); diff --git a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/topic_widget.cpp b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/topic_widget.cpp index 6a0b85629e..9b2c38787f 100644 --- a/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/topic_widget.cpp +++ b/app/mon/mon_gui/src/widgets/ecalmon_tree_widget/topic_widget.cpp @@ -26,7 +26,7 @@ #include "ecalmon.h" -#include +#include #include @@ -85,8 +85,7 @@ TopicWidget::TopicWidget(QWidget *parent) (int)TopicTreeModel::Columns::PROCESS_NAME, (int)TopicTreeModel::Columns::UNIT_NAME, (int)TopicTreeModel::Columns::TOPIC_ENCODING, - (int)TopicTreeModel::Columns::MESSAGE_TYPE, - (int)TopicTreeModel::Columns::QOS, + (int)TopicTreeModel::Columns::TOPIC_TYPE, (int)TopicTreeModel::Columns::TRANSPORT_LAYER, }; setFilterColumns(filter_columns); @@ -100,8 +99,7 @@ TopicWidget::TopicWidget(QWidget *parent) (int)TopicTreeModel::Columns::HOST_NAME, (int)TopicTreeModel::Columns::PROCESS_NAME, (int)TopicTreeModel::Columns::TOPIC_ENCODING, - (int)TopicTreeModel::Columns::MESSAGE_TYPE, - (int)TopicTreeModel::Columns::QOS, + (int)TopicTreeModel::Columns::TOPIC_TYPE, (int)TopicTreeModel::Columns::TRANSPORT_LAYER, }; @@ -132,7 +130,7 @@ TopicWidget::TopicWidget(QWidget *parent) preconfigured_group_by_settings.push_back(encoding); EcalmonTreeWidget::GroupSetting type; - type.group_by_columns = { (int)TopicTreeModel::Columns::MESSAGE_TYPE, (int)TopicTreeModel::Columns::TOPIC_NAME }; + type.group_by_columns = { (int)TopicTreeModel::Columns::TOPIC_TYPE, (int)TopicTreeModel::Columns::TOPIC_NAME }; type.auto_expand = -1; type.name = "Type"; preconfigured_group_by_settings.push_back(type); @@ -155,7 +153,7 @@ TopicWidget::TopicWidget(QWidget *parent) (int)TopicTreeModel::Columns::HOST_NAME, (int)TopicTreeModel::Columns::PID, (int)TopicTreeModel::Columns::TOPIC_ENCODING, - (int)TopicTreeModel::Columns::MESSAGE_TYPE, + (int)TopicTreeModel::Columns::TOPIC_TYPE, (int)TopicTreeModel::Columns::TOPIC_SIZE, (int)TopicTreeModel::Columns::MESSAGE_DROPS, (int)TopicTreeModel::Columns::DATA_CLOCK, @@ -186,19 +184,17 @@ TopicWidget::~TopicWidget() void TopicWidget::loadRegExpLists() { + // TODO: Load regular expressions from eCALMon configuration - QString exclude_string; - QString include_string; - exclude_string = QString::fromStdString(eCAL::Config::GetMonitoringFilterExcludeList()); //ini.GetValue(MON_SECTION_S, MON_FILTER_EXCL_S); + // this is now just taken from the old ecal.yaml/ini configuration + QString exclude_string{ "^__.*$" }; //!< Topics blacklist as regular expression (will not be monitored) (Default: "^__.*$") + QString include_string{ "" }; //!< Topics whitelist as regular expression (will be monitored only) (Default: "") - include_string = QString::fromStdString(eCAL::Config::GetMonitoringFilterIncludeList()); //ini.GetValue(MON_SECTION_S, MON_FILTER_INCL_S); - - - // The ecal.ini defines a very strange regex format: A filter consists of + // The ecal.yaml defines a very strange regex format: A filter consists of // several regular expressions divided by "," or ";". Thus we have to // split the string into 'actual' regular expressions. This will break every // regular expression that properly uses a ",". We cannot do anything about - // that without changing the ecal.ini specification. + // that without changing the ecal.yaml specification. #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QList const exclude_string_list = exclude_string.split(QRegularExpression("[\\,,;]"), Qt::SplitBehaviorFlags::SkipEmptyParts); QList const include_string_list = include_string.split(QRegularExpression("[\\,,;]"), Qt::SplitBehaviorFlags::SkipEmptyParts); @@ -223,16 +219,16 @@ void TopicWidget::autoSizeColumns() eCAL::pb::Topic example_topic_pb; example_topic_pb.set_rclock(999999); - example_topic_pb.set_hname("CARPC00____"); + example_topic_pb.set_hname("HOSTNAME____"); example_topic_pb.set_pid(999999); example_topic_pb.set_pname(""); - example_topic_pb.set_uname("CameraSensorMapFusionCAF___"); + example_topic_pb.set_uname("ATypicalLongUnitName___"); example_topic_pb.set_tid(""); - example_topic_pb.set_tname("CameraSensorMapFusionCAF___"); + example_topic_pb.set_tname("ATypicalLongTopicName___"); example_topic_pb.set_direction("subscriber__"); - example_topic_pb.set_ttype("proto:pb.People.Person____"); - //example_topic_pb.set_tdesc(); - example_topic_pb.mutable_tqos()->set_reliability(eCAL::pb::QOS::eQOSPolicy_Reliability::QOS_eQOSPolicy_Reliability_best_effort_reliability_qos); + example_topic_pb.mutable_tdatatype()->set_name("Enc.TypeName.Name____"); + example_topic_pb.mutable_tdatatype()->set_encoding("encdg:"); + //example_topic_pb.mutable_tdatatype()->set_desc(""); example_topic_pb.mutable_tlayer()->Add()->set_type(eCAL::pb::eTLayerType::tl_ecal_shm); example_topic_pb.mutable_tlayer()->Add()->set_type(eCAL::pb::eTLayerType::tl_ecal_udp_mc); @@ -244,7 +240,7 @@ void TopicWidget::autoSizeColumns() example_topic_pb.set_dfreq(999999); TopicTreeItem* example_topic_item = new TopicTreeItem(example_topic_pb); - GroupTreeItem* example_group_item = new GroupTreeItem("CameraSensorMapFusionCAF___", "", "", QVariant(), ""); + GroupTreeItem* example_group_item = new GroupTreeItem("ATypicalLongGroupName___", "", "", QVariant(), ""); topic_tree_model_->insertItem(example_group_item); auto group_index = topic_tree_model_->index(example_group_item); @@ -263,9 +259,8 @@ void TopicWidget::autoSizeColumns() (int)TopicTreeModel::Columns::HOST_NAME, (int)TopicTreeModel::Columns::PID, (int)TopicTreeModel::Columns::TOPIC_ENCODING, - (int)TopicTreeModel::Columns::MESSAGE_TYPE, + (int)TopicTreeModel::Columns::TOPIC_TYPE, (int)TopicTreeModel::Columns::HEARTBEAT, - (int)TopicTreeModel::Columns::QOS, (int)TopicTreeModel::Columns::TRANSPORT_LAYER, (int)TopicTreeModel::Columns::TOPIC_SIZE, (int)TopicTreeModel::Columns::CONNECTIONS_LOCAL, diff --git a/app/mon/mon_gui/src/widgets/log_widget/log_widget.cpp b/app/mon/mon_gui/src/widgets/log_widget/log_widget.cpp index 2dc7f910d6..fb9c8c15b1 100644 --- a/app/mon/mon_gui/src/widgets/log_widget/log_widget.cpp +++ b/app/mon/mon_gui/src/widgets/log_widget/log_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,12 +54,12 @@ LogWidget::LogWidget(QWidget *parent) : QWidget(parent) , log_update_time_milliseconds_(100) , parse_time_enabled_(true) + , log_model_(new LogModel(this)) + , log_proxy_model_(new LogSortFilterProxyModel(this)) { ui_.setupUi(this); // Tree Model - log_model_ = new LogModel(this); - log_proxy_model_ = new LogSortFilterProxyModel(this); log_proxy_model_->setFilterRole(ItemDataRoles::FilterRole); log_proxy_model_->setSortRole(ItemDataRoles::SortRole); log_proxy_model_->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); @@ -187,10 +187,10 @@ LogWidget::~LogWidget() void LogWidget::getEcalLogs() { - eCAL::pb::Logging logging; - std::string logging_string; + eCAL::pb::LogMessageList logging; + std::string logging_string; - if (eCAL::Monitoring::GetLogging(logging_string)) + if (eCAL::Logging::GetLogging(logging_string) != 0) { logging.ParseFromString(logging_string); } @@ -211,30 +211,30 @@ void LogWidget::getEcalLogs() void LogWidget::updateLogLevelFilter() { - int log_level_filter = eCAL_Logging_eLogLevel::log_level_none; + int log_level_filter = eCAL::Logging::eLogLevel::log_level_none; if (ui_.debug_checkbox->isChecked()) { - log_level_filter |= (eCAL_Logging_eLogLevel::log_level_debug1 | eCAL_Logging_eLogLevel::log_level_debug2 | eCAL_Logging_eLogLevel::log_level_debug3 | eCAL_Logging_eLogLevel::log_level_debug4); + log_level_filter |= (eCAL::Logging::eLogLevel::log_level_debug1 | eCAL::Logging::eLogLevel::log_level_debug2 | eCAL::Logging::eLogLevel::log_level_debug3 | eCAL::Logging::eLogLevel::log_level_debug4); } if (ui_.info_checkbox->isChecked()) { - log_level_filter |= eCAL_Logging_eLogLevel::log_level_info; + log_level_filter |= eCAL::Logging::eLogLevel::log_level_info; } if (ui_.warning_checkbox->isChecked()) { - log_level_filter |= eCAL_Logging_eLogLevel::log_level_warning; + log_level_filter |= eCAL::Logging::eLogLevel::log_level_warning; } if (ui_.error_checkbox->isChecked()) { - log_level_filter |= eCAL_Logging_eLogLevel::log_level_error; + log_level_filter |= eCAL::Logging::eLogLevel::log_level_error; } if (ui_.fatal_checkbox->isChecked()) { - log_level_filter |= eCAL_Logging_eLogLevel::log_level_fatal; + log_level_filter |= eCAL::Logging::eLogLevel::log_level_fatal; } - log_proxy_model_->setLogLevelFilter((eCAL_Logging_eLogLevel)log_level_filter); + log_proxy_model_->setLogLevelFilter((eCAL::Logging::eLogLevel)log_level_filter); } void LogWidget::setPaused(bool paused) @@ -402,11 +402,11 @@ void LogWidget::setLogLevelFilter(int log_level) ui_.error_checkbox ->blockSignals(true); ui_.fatal_checkbox ->blockSignals(true); - ui_.debug_checkbox ->setChecked(log_level & (eCAL_Logging_eLogLevel::log_level_debug1 | eCAL_Logging_eLogLevel::log_level_debug2 | eCAL_Logging_eLogLevel::log_level_debug3 | eCAL_Logging_eLogLevel::log_level_debug4)); - ui_.info_checkbox ->setChecked(log_level & eCAL_Logging_eLogLevel::log_level_info); - ui_.warning_checkbox->setChecked(log_level & eCAL_Logging_eLogLevel::log_level_warning); - ui_.error_checkbox ->setChecked(log_level & eCAL_Logging_eLogLevel::log_level_error); - ui_.fatal_checkbox ->setChecked(log_level & eCAL_Logging_eLogLevel::log_level_fatal); + ui_.debug_checkbox ->setChecked(log_level & (eCAL::Logging::eLogLevel::log_level_debug1 | eCAL::Logging::eLogLevel::log_level_debug2 | eCAL::Logging::eLogLevel::log_level_debug3 | eCAL::Logging::eLogLevel::log_level_debug4)); + ui_.info_checkbox ->setChecked(log_level & eCAL::Logging::eLogLevel::log_level_info); + ui_.warning_checkbox->setChecked(log_level & eCAL::Logging::eLogLevel::log_level_warning); + ui_.error_checkbox ->setChecked(log_level & eCAL::Logging::eLogLevel::log_level_error); + ui_.fatal_checkbox ->setChecked(log_level & eCAL::Logging::eLogLevel::log_level_fatal); updateLogLevelFilter(); @@ -420,7 +420,7 @@ void LogWidget::setLogLevelFilter(int log_level) void LogWidget::contextMenu(const QPoint &pos) { auto selected_proxy_rows = ui_.log_tree->selectionModel()->selectedRows(LogModel::Columns::TIME); - if (selected_proxy_rows.size() > 0) + if (!selected_proxy_rows.empty()) { QMenu context_menu(this); @@ -443,7 +443,7 @@ void LogWidget::copySelectedRows() for (auto& proxy_row : selected_proxy_rows) { bool first_element = true; - auto ui_log_tree_model = ui_.log_tree->model(); + auto *ui_log_tree_model = ui_.log_tree->model(); for (int column = 0; column < ui_log_tree_model->columnCount(); column++) { if (!ui_.log_tree->isColumnHidden(column)) diff --git a/app/mon/mon_gui/src/widgets/log_widget/log_widget.h b/app/mon/mon_gui/src/widgets/log_widget/log_widget.h index e13957d443..33e5a22d4c 100644 --- a/app/mon/mon_gui/src/widgets/log_widget/log_widget.h +++ b/app/mon/mon_gui/src/widgets/log_widget/log_widget.h @@ -61,7 +61,7 @@ private slots: void paused(bool paused); private: - Ui::LogWidget ui_; + Ui::LogWidget ui_{}; QTimer* log_update_timer_; int log_update_time_milliseconds_; @@ -81,8 +81,8 @@ private slots: }; QByteArray initial_tree_state_; - int initial_log_level_filter_; - bool initial_auto_scroll_; + int initial_log_level_filter_{}; + bool initial_auto_scroll_{}; void saveGuiSettings(); diff --git a/app/mon/mon_gui/src/widgets/models/host_tree_item.cpp b/app/mon/mon_gui/src/widgets/models/host_tree_item.cpp index 15e084c5ef..74d04c2608 100644 --- a/app/mon/mon_gui/src/widgets/models/host_tree_item.cpp +++ b/app/mon/mon_gui/src/widgets/models/host_tree_item.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -167,8 +167,9 @@ void HostTreeItem::update(const eCAL::pb::Monitoring& monitoring_pb) data_received_bytes_ = 0; // Fill variables with accumulated data - for (auto topic : monitoring_pb.topics()) + for (int i = 0; i +#include #ifdef _MSC_VER #pragma warning(pop) #endif @@ -73,7 +73,7 @@ class LogModel : public QAbstractItemModel QModelIndex parent(const QModelIndex &index) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; - void insertLogs(const eCAL::pb::Logging& logs); + void insertLogs(const eCAL::pb::LogMessageList& logs); void setParseTimeEnabled(bool enabled); bool isParseTimeEnabled() const; diff --git a/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.cpp b/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.cpp index 259461b6b9..00fbc36ab2 100644 --- a/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.cpp +++ b/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ #include "item_data_roles.h" LogSortFilterProxyModel::LogSortFilterProxyModel(QObject* parent) - : QMulticolumnSortFilterProxyModel(parent), log_level_filter_(log_level_none) + : QMulticolumnSortFilterProxyModel(parent), log_level_filter_(eCAL::Logging::eLogLevel::log_level_none) { setRecursiveFilteringEnabled(true); } @@ -44,13 +44,13 @@ bool LogSortFilterProxyModel::filterDirectAcceptsRow(int source_row, const QMode return false; } -void LogSortFilterProxyModel::setLogLevelFilter(eCAL_Logging_eLogLevel log_levels) +void LogSortFilterProxyModel::setLogLevelFilter(eCAL::Logging::eLogLevel log_levels) { log_level_filter_ = log_levels; invalidateFilter(); } -eCAL_Logging_eLogLevel LogSortFilterProxyModel::logLevelFilter() const +eCAL::Logging::eLogLevel LogSortFilterProxyModel::logLevelFilter() const { return log_level_filter_; } \ No newline at end of file diff --git a/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.h b/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.h index 37d91bd5df..573f69459b 100644 --- a/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.h +++ b/app/mon/mon_gui/src/widgets/models/log_sort_filter_proxy_model.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,12 +29,12 @@ class LogSortFilterProxyModel : LogSortFilterProxyModel(QObject* parent = 0); ~LogSortFilterProxyModel(); - void setLogLevelFilter(eCAL_Logging_eLogLevel log_levels); + void setLogLevelFilter(eCAL::Logging::eLogLevel log_levels); - eCAL_Logging_eLogLevel logLevelFilter() const; + eCAL::Logging::eLogLevel logLevelFilter() const; private: - eCAL_Logging_eLogLevel log_level_filter_; + eCAL::Logging::eLogLevel log_level_filter_; bool filterDirectAcceptsRow(int source_row, const QModelIndex &source_parent) const override; }; diff --git a/app/mon/mon_gui/src/widgets/models/process_tree_item.cpp b/app/mon/mon_gui/src/widgets/models/process_tree_item.cpp index ec10163745..cc1509083a 100644 --- a/app/mon/mon_gui/src/widgets/models/process_tree_item.cpp +++ b/app/mon/mon_gui/src/widgets/models/process_tree_item.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -61,9 +61,9 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const { return process_.hname().c_str(); } - else if (column == Columns::HGNAME) + else if (column == Columns::SHM_TRANSPORT_DOMAIN) { - return process_.hgname().c_str(); + return process_.shm_transport_domain().c_str(); } else if (column == Columns::PID) { @@ -81,26 +81,6 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const { return process_.pparam().c_str(); } - else if (column == Columns::PMEMORY) - { - return (long long)process_.pmemory(); - } - else if (column == Columns::PCPU) - { - return (long long)process_.pcpu(); - } - else if (column == Columns::USRPTIME) - { - return process_.usrptime(); - } - else if (column == Columns::DATAWRITE) - { - return (long long)process_.datawrite(); - } - else if (column == Columns::DATAREAD) - { - return (long long)process_.dataread(); - } else if (column == Columns::SEVERITY) { severityToCombinedInt(process_.state().severity(), process_.state().severity_level()); @@ -125,6 +105,10 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const { return process_.ecal_runtime_version().c_str(); } + else if (column == Columns::CONFIG_FILE_PATH) + { + return process_.config_file_path().c_str(); + } else { return QVariant(); @@ -134,37 +118,13 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const else if ((role == Qt::ItemDataRole::DisplayRole) || (role == Qt::ItemDataRole::ToolTipRole)) { if ((column == Columns::HNAME) - || (column == Columns::HGNAME) + || (column == Columns::SHM_TRANSPORT_DOMAIN) || (column == Columns::PNAME) || (column == Columns::UNAME)) { QString raw_data = data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole).toString(); //-V1016 return (!raw_data.isEmpty() ? raw_data : "- ? -"); } - else if (column == Columns::PMEMORY) - { - auto memory_bytes = process_.pmemory(); - if (memory_bytes == 0) - { - return "0"; - } - else - { - return QString::number(memory_bytes / 1024.0, 'f', 0); - } - } - else if (column == Columns::PCPU) - { - double cpu_percentage = process_.pcpu(); - if (fabs(cpu_percentage) < DBL_EPSILON) - { - return "0"; - } - else - { - return QString::number(cpu_percentage, 'f', 2); - } - } else if (column == Columns::SEVERITY) { return severityToString(process_.state().severity(), process_.state().severity_level()); @@ -197,7 +157,7 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const else if (role == (Qt::ItemDataRole)ItemDataRoles::FilterRole) //-V1016 //-V547 { if ((column == Columns::HNAME) - || (column == Columns::HGNAME) + || (column == Columns::SHM_TRANSPORT_DOMAIN) || (column == Columns::PNAME) || (column == Columns::UNAME)) { @@ -227,11 +187,6 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const { if ((column == Columns::RCLOCK) || (column == Columns::PID) - || (column == Columns::PMEMORY) - || (column == Columns::PCPU) - || (column == Columns::USRPTIME) - || (column == Columns::DATAWRITE) - || (column == Columns::DATAREAD) ) { return Qt::AlignmentFlag::AlignRight; @@ -288,7 +243,7 @@ QVariant ProcessTreeItem::data(Columns column, Qt::ItemDataRole role) const else if (role == Qt::ItemDataRole::FontRole) { if ((column == Columns::HNAME) - || (column == Columns::HGNAME) + || (column == Columns::SHM_TRANSPORT_DOMAIN) || (column == Columns::PNAME) || (column == Columns::UNAME)) { diff --git a/app/mon/mon_gui/src/widgets/models/process_tree_item.h b/app/mon/mon_gui/src/widgets/models/process_tree_item.h index 2088ba4d04..c25586771a 100644 --- a/app/mon/mon_gui/src/widgets/models/process_tree_item.h +++ b/app/mon/mon_gui/src/widgets/models/process_tree_item.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,22 +39,18 @@ class ProcessTreeItem : { RCLOCK, HNAME, - HGNAME, + SHM_TRANSPORT_DOMAIN, PID, PNAME, UNAME, PPARAM, - PMEMORY, - PCPU, - USRPTIME, - DATAWRITE, - DATAREAD, SEVERITY, INFO, TSYNC_STATE, TSYNC_MOD_NAME, COMPONENT_INIT_INFO, - ECAL_RUNTIME_VERSION + ECAL_RUNTIME_VERSION, + CONFIG_FILE_PATH }; ProcessTreeItem(); diff --git a/app/mon/mon_gui/src/widgets/models/process_tree_model.h b/app/mon/mon_gui/src/widgets/models/process_tree_model.h index 5a4adb56cf..8a26f57727 100644 --- a/app/mon/mon_gui/src/widgets/models/process_tree_model.h +++ b/app/mon/mon_gui/src/widgets/models/process_tree_model.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,22 +48,18 @@ class ProcessTreeModel : public GroupTreeModel GROUP, UNIT_NAME, HOST_NAME, - HOST_GROUP_NAME, + SHM_TRANSPORT_DOMAIN, PID, PROCESS_NAME, PARAMETERS, STATE, INFO, HEARTBEAT, - MEMORY, - CPU_PERCENTAGE, - USER_TIME, - DATAWRITE, - DATAREAD, TIMESYNC_STATE, TIMESYNC_MOD_NAME, COMPONENT_INIT_INFO, ECAL_RUNTIME_VERSION, + CONFIG_FILE_PATH, COLUMN_COUNT }; @@ -89,22 +85,18 @@ class ProcessTreeModel : public GroupTreeModel { Columns::GROUP, "Group" }, { Columns::UNIT_NAME, "Process" }, { Columns::HOST_NAME, "Host" }, - { Columns::HOST_GROUP_NAME, "Host Group" }, + { Columns::SHM_TRANSPORT_DOMAIN, "Host Group" }, { Columns::PID, "PID" }, { Columns::PROCESS_NAME, "Process Path" }, { Columns::PARAMETERS, "Command line" }, { Columns::STATE, "State" }, { Columns::INFO, "Info" }, { Columns::HEARTBEAT, "Heartbeat" }, - { Columns::MEMORY, "RAM [KiB]" }, - { Columns::CPU_PERCENTAGE, "CPU %" }, - { Columns::USER_TIME, "User Time" }, - { Columns::DATAWRITE, "Data Write [Byte/s]" }, - { Columns::DATAREAD, "Data Read [Byte/s]" }, { Columns::TIMESYNC_STATE, "Timesync State" }, { Columns::TIMESYNC_MOD_NAME, "Timesync Mod Name" }, { Columns::COMPONENT_INIT_INFO, "Component Initialization" }, { Columns::ECAL_RUNTIME_VERSION, "eCAL Runtime Version" }, + { Columns::CONFIG_FILE_PATH, "Loaded configuration file" }, }; std::map column_mapping = @@ -112,22 +104,18 @@ class ProcessTreeModel : public GroupTreeModel { Columns::GROUP, -1 }, { Columns::UNIT_NAME, (int)ProcessTreeItem::Columns::UNAME }, { Columns::HOST_NAME, (int)ProcessTreeItem::Columns::HNAME }, - { Columns::HOST_GROUP_NAME, (int)ProcessTreeItem::Columns::HGNAME}, + { Columns::SHM_TRANSPORT_DOMAIN, (int)ProcessTreeItem::Columns::SHM_TRANSPORT_DOMAIN}, { Columns::PID, (int)ProcessTreeItem::Columns::PID }, { Columns::PROCESS_NAME, (int)ProcessTreeItem::Columns::PNAME }, { Columns::PARAMETERS, (int)ProcessTreeItem::Columns::PPARAM }, { Columns::STATE, (int)ProcessTreeItem::Columns::SEVERITY }, { Columns::INFO, (int)ProcessTreeItem::Columns::INFO }, { Columns::HEARTBEAT, (int)ProcessTreeItem::Columns::RCLOCK }, - { Columns::CPU_PERCENTAGE, (int)ProcessTreeItem::Columns::PCPU }, - { Columns::MEMORY, (int)ProcessTreeItem::Columns::PMEMORY }, - { Columns::USER_TIME, (int)ProcessTreeItem::Columns::USRPTIME }, - { Columns::DATAWRITE, (int)ProcessTreeItem::Columns::DATAWRITE }, - { Columns::DATAREAD, (int)ProcessTreeItem::Columns::DATAREAD }, { Columns::TIMESYNC_STATE, (int)ProcessTreeItem::Columns::TSYNC_STATE }, { Columns::TIMESYNC_MOD_NAME, (int)ProcessTreeItem::Columns::TSYNC_MOD_NAME }, { Columns::COMPONENT_INIT_INFO, (int)ProcessTreeItem::Columns::COMPONENT_INIT_INFO }, { Columns::ECAL_RUNTIME_VERSION, (int)ProcessTreeItem::Columns::ECAL_RUNTIME_VERSION }, + { Columns::CONFIG_FILE_PATH, (int)ProcessTreeItem::Columns::CONFIG_FILE_PATH }, }; std::map tree_item_map_; diff --git a/app/mon/mon_gui/src/widgets/models/service_tree_item.cpp b/app/mon/mon_gui/src/widgets/models/service_tree_item.cpp deleted file mode 100644 index 45bda0981e..0000000000 --- a/app/mon/mon_gui/src/widgets/models/service_tree_item.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ========================= eCAL LICENSE ================================= -*/ - -#include "service_tree_item.h" - -#include -#include - -#include "item_data_roles.h" - -#include "tree_item_type.h" - -ServiceTreeItem::ServiceTreeItem() - : QAbstractTreeItem() - , identifier_("") -{ -} - -ServiceTreeItem::ServiceTreeItem(const eCAL::pb::Service& service, const eCAL::pb::Method& method) - : QAbstractTreeItem() - , identifier_("") -{ - update(service, method); -} - -ServiceTreeItem::~ServiceTreeItem() -{ -} - -QVariant ServiceTreeItem::data(int column, Qt::ItemDataRole role) const -{ - return data((Columns)column, role); -} - -QVariant ServiceTreeItem::data(Columns column, Qt::ItemDataRole role) const -{ - if (role == (Qt::ItemDataRole)ItemDataRoles::RawDataRole) //-V1016 //-V547 - { - if (column == Columns::RCLOCK) - { - return service_.rclock(); - } - else if (column == Columns::HNAME) - { - return service_.hname().c_str(); - } - else if (column == Columns::PNAME) - { - return service_.pname().c_str(); - } - else if (column == Columns::UNAME) - { - return service_.uname().c_str(); - } - else if (column == Columns::PID) - { - return service_.pid(); - } - else if (column == Columns::SNAME) - { - return service_.sname().c_str(); - } - else if (column == Columns::TCP_PORT) - { - return service_.tcp_port_v1(); - } - else if (column == Columns::MNAME) - { - return method_.mname().c_str(); - } - else if (column == Columns::REQ_TYPE) - { - return method_.req_type().c_str(); - } - else if (column == Columns::RESP_TYPE) - { - return method_.resp_type().c_str(); - } - else if (column == Columns::CALL_COUNT) - { - return (long long)method_.call_count(); - } - else - { - return QVariant(); - } - } - - else if ((role == Qt::ItemDataRole::DisplayRole) || (role == Qt::ItemDataRole::ToolTipRole)) - { - if ((column == Columns::HNAME) - || (column == Columns::PNAME) - || (column == Columns::UNAME) - || (column == Columns::SNAME) - || (column == Columns::MNAME) - || (column == Columns::REQ_TYPE) - || (column == Columns::RESP_TYPE)) - { - QString raw_data = data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole).toString(); //-V1016 - return (!raw_data.isEmpty() ? raw_data : "- ? -"); - } - else - { - return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 - } - } - - else if (role == ItemDataRoles::SortRole) //-V547 - { - return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 - } - - else if (role == ItemDataRoles::FilterRole) //-V547 - { - return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 - } - - else if (role == Qt::ItemDataRole::TextAlignmentRole) - { - if ((column == Columns::RCLOCK) - || (column == Columns::PID) - || (column == Columns::TCP_PORT) - || (column == Columns::CALL_COUNT) - ) - { - return Qt::AlignmentFlag::AlignRight; - } - else - { - return Qt::AlignmentFlag::AlignLeft; - } - } - - else if (role == ItemDataRoles::GroupRole) //-V547 - { - if (column == Columns::PNAME) - { - QStringList list{service_.hname().c_str(), service_.pname().c_str()}; - return list; - } - else if (column == Columns::PID) - { - QStringList list{ service_.hname().c_str(), QString::number(service_.pid()) }; - return list; - } - else if (column == Columns::UNAME) - { - QStringList list{ service_.hname().c_str(), service_.uname().c_str(), QString::number(service_.pid()) }; - return list; - } - else if (column == Columns::SNAME) - { - QStringList list{ service_.sname().c_str(), service_.hname().c_str(), service_.uname().c_str(), QString::number(service_.pid()) }; - return list; - } - else - { - return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 - } - } - - else if (role == Qt::ItemDataRole::FontRole) - { - if ((column == Columns::HNAME) - || (column == Columns::PNAME) - || (column == Columns::UNAME) - || (column == Columns::SNAME) - || (column == Columns::MNAME) - || (column == Columns::REQ_TYPE) - || (column == Columns::RESP_TYPE)) - { - QString raw_data = data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole).toString(); //-V1016 - if (raw_data.isEmpty()) - { - QFont font; - font.setItalic(true); - return font; - } - else - { - return QVariant(); // Invalid QVariant - } - } - else - { - return QVariant(); // Invalid QVariant - } - } - - return QVariant(); // Invalid QVariant -} - -int ServiceTreeItem::type() const -{ - return (int)TreeItemType::Service; -} - -std::string ServiceTreeItem::generateIdentifier(const eCAL::pb::Service& service, const eCAL::pb::Method& method) -{ - return std::to_string(service.pid()) + "@" + service.hname() + "@" + method.mname(); -} - -std::string ServiceTreeItem::identifier() const -{ - return identifier_; -} - -void ServiceTreeItem::update(const eCAL::pb::Service& service, const eCAL::pb::Method& method) -{ - service_.Clear(); - service_.CopyFrom(service); - method_.Clear(); - method_.CopyFrom(method); - identifier_ = generateIdentifier(service_, method_); -} diff --git a/app/mon/mon_gui/src/widgets/models/service_tree_item.h b/app/mon/mon_gui/src/widgets/models/service_tree_item.h index 41ecc9f228..624abd336e 100644 --- a/app/mon/mon_gui/src/widgets/models/service_tree_item.h +++ b/app/mon/mon_gui/src/widgets/models/service_tree_item.h @@ -21,6 +21,14 @@ #include "CustomQt/QAbstractTreeItem.h" +#include +#include + +#include + +#include "item_data_roles.h" +#include "tree_item_type.h" + #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4100 4127 4146 4505 4800 4189 4592) // disable proto warnings @@ -30,6 +38,7 @@ #pragma warning(pop) #endif +template class ServiceTreeItem : public QAbstractTreeItem { @@ -43,6 +52,7 @@ class ServiceTreeItem : UNAME, PID, SNAME, + STYPE, TCP_PORT, MNAME, REQ_TYPE, @@ -50,24 +60,225 @@ class ServiceTreeItem : CALL_COUNT, }; - ServiceTreeItem(); - ServiceTreeItem(const eCAL::pb::Service& service, const eCAL::pb::Method& method); + ServiceTreeItem() : QAbstractTreeItem() + { + } + + ServiceTreeItem(const T& service, const eCAL::pb::Method& method) + : QAbstractTreeItem() + { + update(service, method); + + } + + QVariant data(int column, Qt::ItemDataRole role = Qt::ItemDataRole::DisplayRole) const override + { + return data((Columns)column, role); + } + + QVariant data(Columns column, Qt::ItemDataRole role = Qt::ItemDataRole::DisplayRole) const + { + if (role == (Qt::ItemDataRole)ItemDataRoles::RawDataRole) //-V1016 //-V547 + { + if (column == Columns::RCLOCK) + { + return service_.rclock(); + } + else if (column == Columns::HNAME) + { + return service_.hname().c_str(); + } + else if (column == Columns::PNAME) + { + return service_.pname().c_str(); + } + else if (column == Columns::UNAME) + { + return service_.uname().c_str(); + } + else if (column == Columns::PID) + { + return service_.pid(); + } + else if (column == Columns::SNAME) + { + return service_.sname().c_str(); + } + else if (column == Columns::STYPE) + { + return std::is_same::value ? "Server" : "Client"; + } + else if (column == Columns::TCP_PORT) + { + return tcpPort() != 0 ? tcpPort() : QVariant(); + } + else if (column == Columns::MNAME) + { + return method_.mname().c_str(); + } + else if (column == Columns::REQ_TYPE) + { + return method_.req_type().c_str(); + } + else if (column == Columns::RESP_TYPE) + { + return method_.resp_type().c_str(); + } + else if (column == Columns::CALL_COUNT) + { + return (long long)method_.call_count(); + } + else + { + return QVariant(); + } + } + else if ((role == Qt::ItemDataRole::DisplayRole) || (role == Qt::ItemDataRole::ToolTipRole)) + { + if ((column == Columns::HNAME) + || (column == Columns::PNAME) + || (column == Columns::UNAME) + || (column == Columns::SNAME) + || (column == Columns::MNAME) + || (column == Columns::REQ_TYPE) + || (column == Columns::RESP_TYPE)) + { + QString raw_data = data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole).toString(); //-V1016 + return (!raw_data.isEmpty() ? raw_data : "- ? -"); + } + else + { + return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 + } + } + + else if (role == ItemDataRoles::SortRole) //-V547 + { + return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 + } + + else if (role == ItemDataRoles::FilterRole) //-V547 + { + return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 + } + + else if (role == Qt::ItemDataRole::TextAlignmentRole) + { + if ((column == Columns::RCLOCK) + || (column == Columns::PID) + || (column == Columns::TCP_PORT) + || (column == Columns::CALL_COUNT) + ) + { + return Qt::AlignmentFlag::AlignRight; + } + else + { + return Qt::AlignmentFlag::AlignLeft; + } + } + + else if (role == ItemDataRoles::GroupRole) //-V547 + { + if (column == Columns::PNAME) + { + QStringList list{ service_.hname().c_str(), service_.pname().c_str() }; + return list; + } + else if (column == Columns::PID) + { + QStringList list{ service_.hname().c_str(), QString::number(service_.pid()) }; + return list; + } + else if (column == Columns::UNAME) + { + QStringList list{ service_.hname().c_str(), service_.uname().c_str(), QString::number(service_.pid()) }; + return list; + } + else if (column == Columns::SNAME) + { + QStringList list{ service_.sname().c_str(), service_.hname().c_str(), service_.uname().c_str(), QString::number(service_.pid()) }; + return list; + } + else + { + return data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole); //-V1016 + } + } - ~ServiceTreeItem(); + else if (role == Qt::ItemDataRole::FontRole) + { + if ((column == Columns::HNAME) + || (column == Columns::PNAME) + || (column == Columns::UNAME) + || (column == Columns::SNAME) + || (column == Columns::STYPE) + || (column == Columns::MNAME) + || (column == Columns::REQ_TYPE) + || (column == Columns::RESP_TYPE)) + { + QString raw_data = data(column, (Qt::ItemDataRole)ItemDataRoles::RawDataRole).toString(); //-V1016 + if (raw_data.isEmpty()) + { + QFont font; + font.setItalic(true); + return font; + } + else + { + return QVariant(); // Invalid QVariant + } + } + else + { + return QVariant(); // Invalid QVariant + } + } - QVariant data(int column, Qt::ItemDataRole role = Qt::ItemDataRole::DisplayRole) const; + return QVariant(); // Invalid QVariant + } - QVariant data(Columns column, Qt::ItemDataRole role = Qt::ItemDataRole::DisplayRole) const; + int type() const override + { + return (int)TreeItemType::Service; + } - int type() const; + std::string identifier() const + { + return identifier_; + } - std::string identifier() const; - static std::string generateIdentifier(const eCAL::pb::Service& service, const eCAL::pb::Method& method); + static std::string generateIdentifier(const T& service, const eCAL::pb::Method& method) + { + return std::to_string(service.pid()) + "@" + service.hname() + "@" + service.sname() + "@" + method.mname(); + } - void update(const eCAL::pb::Service& service, const eCAL::pb::Method& method); + void update(const T& service, const eCAL::pb::Method& method) + { + service_.Clear(); + service_.CopyFrom(service); + method_.Clear(); + method_.CopyFrom(method); + identifier_ = generateIdentifier(service_, method_); + } private: - eCAL::pb::Service service_; + // This workaround is required to utilize this template class with + // eCAL::pb::Client even though it has no tcp_port_v1() signature + // exposed. However, when upgrading eCAL to a newer C++ standard + // in the future, the workaround can be replace with if constexpr. + template + typename std::enable_if::value, int>::type + tcpPort() const { + return service_.tcp_port_v1(); + } + template + typename std::enable_if::value, int>::type + tcpPort() const { + return 0; + } + + T service_; eCAL::pb::Method method_; std::string identifier_; }; diff --git a/app/mon/mon_gui/src/widgets/models/service_tree_model.cpp b/app/mon/mon_gui/src/widgets/models/service_tree_model.cpp index eb448f3024..9b9e060970 100644 --- a/app/mon/mon_gui/src/widgets/models/service_tree_model.cpp +++ b/app/mon/mon_gui/src/widgets/models/service_tree_model.cpp @@ -69,41 +69,79 @@ int ServiceTreeModel::groupColumn() const void ServiceTreeModel::monitorUpdated(const eCAL::pb::Monitoring& monitoring_pb) { // Create a list of all service methods to check if we have to remove them - std::map service_still_existing; - for(const auto& service_tree_item : tree_item_map_) + std::map server_still_existing; + for(const auto& server_tree_item : tree_item_server_map_) { - service_still_existing[service_tree_item.first] = false; + server_still_existing[server_tree_item.first] = false; + } + + std::map client_still_existing; + for (const auto& client_tree_item : tree_item_client_map_) + { + client_still_existing[client_tree_item.first] = false; } for (const auto& service : monitoring_pb.services()) { for (const auto& method : service.methods()) { - std::string service_identifier = ServiceTreeItem::generateIdentifier(service, method); + const std::string service_identifier = ServiceTreeItem::generateIdentifier(service, method); + + if (tree_item_server_map_.find(service_identifier) == tree_item_server_map_.end()) + { + // Got a new server-method + auto* const server_tree_item = new ServiceTreeItem(service, method); + insertItemIntoGroups(server_tree_item); + tree_item_server_map_[service_identifier] = server_tree_item; + } + else + { + // Update an existing server-method + tree_item_server_map_.at(service_identifier)->update(service, method); + server_still_existing[service_identifier] = true; + } + } + } + + for (const auto& client : monitoring_pb.clients()) + { + for (const auto& method : client.methods()) + { + const std::string client_identifier = ServiceTreeItem::generateIdentifier(client, method); - if (tree_item_map_.find(service_identifier) == tree_item_map_.end()) + if (tree_item_client_map_.find(client_identifier) == tree_item_client_map_.end()) { - // Got a new service-method - ServiceTreeItem* service_tree_item = new ServiceTreeItem(service, method); - insertItemIntoGroups(service_tree_item); - tree_item_map_[service_identifier] = service_tree_item; + // Got a new client-method + auto* const client_tree_item = new ServiceTreeItem(client, method); + insertItemIntoGroups(client_tree_item); + tree_item_client_map_[client_identifier] = client_tree_item; } else { - // Update an existing service-method - tree_item_map_.at(service_identifier)->update(service, method); - service_still_existing[service_identifier] = true; + // Update an existing client-method + tree_item_client_map_.at(client_identifier)->update(client, method); + client_still_existing[client_identifier] = true; } } } // Remove obsolete items - for (const auto& service_tree_item : service_still_existing) + for (const auto& server_tree_item : server_still_existing) + { + if (!server_tree_item.second) + { + removeItemFromGroups(tree_item_server_map_.at(server_tree_item.first)); + tree_item_server_map_.erase(server_tree_item.first); + } + } + + // Remove obsolete items + for (const auto& client_tree_item : client_still_existing) { - if (!service_tree_item.second) + if (!client_tree_item.second) { - removeItemFromGroups(tree_item_map_.at(service_tree_item.first)); - tree_item_map_.erase(service_tree_item.first); + removeItemFromGroups(tree_item_client_map_.at(client_tree_item.first)); + tree_item_client_map_.erase(client_tree_item.first); } } diff --git a/app/mon/mon_gui/src/widgets/models/service_tree_model.h b/app/mon/mon_gui/src/widgets/models/service_tree_model.h index 55b34a0fea..557ff0a08f 100644 --- a/app/mon/mon_gui/src/widgets/models/service_tree_model.h +++ b/app/mon/mon_gui/src/widgets/models/service_tree_model.h @@ -46,6 +46,7 @@ class ServiceTreeModel : public GroupTreeModel { GROUP, UNIT_NAME, + SERVICE_TYPE, SERVICE_NAME, PROCESS_NAME, HOST_NAME, @@ -85,6 +86,7 @@ class ServiceTreeModel : public GroupTreeModel { Columns::PROCESS_NAME, "Process Path" }, { Columns::UNIT_NAME, "Process" }, { Columns::SERVICE_NAME, "Service" }, + { Columns::SERVICE_TYPE, "Type" }, { Columns::TCP_PORT, "TCP Port" }, { Columns::METHOD_NAME, "Method" }, { Columns::METHOD_REQUEST_TYPE, "Req. Type" }, @@ -95,18 +97,20 @@ class ServiceTreeModel : public GroupTreeModel std::map tree_item_column_mapping = { { Columns::GROUP, -1 }, - { Columns::HEARTBEAT, (int)ServiceTreeItem::Columns::RCLOCK }, - { Columns::HOST_NAME, (int)ServiceTreeItem::Columns::HNAME }, - { Columns::PID, (int)ServiceTreeItem::Columns::PID }, - { Columns::PROCESS_NAME, (int)ServiceTreeItem::Columns::PNAME }, - { Columns::UNIT_NAME, (int)ServiceTreeItem::Columns::UNAME }, - { Columns::SERVICE_NAME, (int)ServiceTreeItem::Columns::SNAME }, - { Columns::TCP_PORT, (int)ServiceTreeItem::Columns::TCP_PORT }, - { Columns::METHOD_NAME, (int)ServiceTreeItem::Columns::MNAME }, - { Columns::METHOD_REQUEST_TYPE, (int)ServiceTreeItem::Columns::REQ_TYPE }, - { Columns::METHOD_RESPONSE_TYPE, (int)ServiceTreeItem::Columns::RESP_TYPE }, - { Columns::CALL_COUNT, (int)ServiceTreeItem::Columns::CALL_COUNT }, + { Columns::HEARTBEAT, (int)ServiceTreeItem::Columns::RCLOCK }, + { Columns::HOST_NAME, (int)ServiceTreeItem::Columns::HNAME }, + { Columns::PID, (int)ServiceTreeItem::Columns::PID }, + { Columns::PROCESS_NAME, (int)ServiceTreeItem::Columns::PNAME }, + { Columns::UNIT_NAME, (int)ServiceTreeItem::Columns::UNAME }, + { Columns::SERVICE_NAME, (int)ServiceTreeItem::Columns::SNAME }, + { Columns::SERVICE_TYPE, (int)ServiceTreeItem::Columns::STYPE }, + { Columns::TCP_PORT, (int)ServiceTreeItem::Columns::TCP_PORT }, + { Columns::METHOD_NAME, (int)ServiceTreeItem::Columns::MNAME }, + { Columns::METHOD_REQUEST_TYPE, (int)ServiceTreeItem::Columns::REQ_TYPE }, + { Columns::METHOD_RESPONSE_TYPE, (int)ServiceTreeItem::Columns::RESP_TYPE }, + { Columns::CALL_COUNT, (int)ServiceTreeItem::Columns::CALL_COUNT }, }; - std::map tree_item_map_; + std::map*> tree_item_client_map_; + std::map*> tree_item_server_map_; }; diff --git a/app/mon/mon_gui/src/widgets/models/topic_tree_item.cpp b/app/mon/mon_gui/src/widgets/models/topic_tree_item.cpp index 7b41c1fe04..296200e167 100644 --- a/app/mon/mon_gui/src/widgets/models/topic_tree_item.cpp +++ b/app/mon/mon_gui/src/widgets/models/topic_tree_item.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,9 +52,9 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const { return topic_.hname().c_str(); } - else if (column == Columns::HGNAME) + else if (column == Columns::SHM_TRANSPORT_DOMAIN) { - return topic_.hgname().c_str(); + return topic_.shm_transport_domain().c_str(); } else if (column == Columns::PID) { @@ -82,78 +82,16 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const } else if (column == Columns::TENCODING) { - // When the monitor didn't tell us the topic encoding, we ask eCAL::Util instead - // Why this logic only for type, not descriptor? (and thus encoding?) - const std::string monitor_topic_encoding = topic_.tdatatype().encoding(); - if (!monitor_topic_encoding.empty()) - { - return monitor_topic_encoding.c_str(); - } - else - { - const std::string monitor_topic_name = topic_.tname(); - if (!monitor_topic_name.empty()) - { - eCAL::SDataTypeInformation topic_info; - eCAL::Util::GetTopicDataTypeInformation(monitor_topic_name, topic_info); - return topic_info.encoding.c_str(); - } - } + return topic_.tdatatype().encoding().c_str(); } else if (column == Columns::TTYPE) { - // When the monitor didn't tell us the topic type, we ask eCAL::Util instead - // Why this logic only for type, not descriptor? (and thus encoding?) - const std::string monitor_topic_type = topic_.tdatatype().name(); - if (!monitor_topic_type.empty()) - { - return monitor_topic_type.c_str(); - } - else - { - const std::string monitor_topic_name = topic_.tname(); - if (!monitor_topic_name.empty()) - { - eCAL::SDataTypeInformation topic_info; - eCAL::Util::GetTopicDataTypeInformation(monitor_topic_name, topic_info); - return topic_info.name.c_str(); - } - } + return topic_.tdatatype().name().c_str(); } else if (column == Columns::TDESC) { return topic_.tdatatype().desc().c_str(); } - else if (column == Columns::TQOS) - { - auto reliability = topic_.tqos().reliability(); - - QString qos_string; - - if (reliability == eCAL::pb::QOS::eQOSPolicy_Reliability::QOS_eQOSPolicy_Reliability_reliable_reliability_qos) - { - auto topic_tqos = topic_.tqos(); - qos_string += "Reliable"; - - auto history = topic_tqos.history(); - if (history == eCAL::pb::QOS::eQOSPolicy_HistoryKind::QOS_eQOSPolicy_HistoryKind_keep_all_history_qos) - { - qos_string += " (History: unlimited)"; - } - else if (history == eCAL::pb::QOS::eQOSPolicy_HistoryKind::QOS_eQOSPolicy_HistoryKind_keep_last_history_qos) - { - qos_string += (" (History: " + QString::number(topic_tqos.history_depth()) + ")"); - } - } - else - { - if (reliability == eCAL::pb::QOS::eQOSPolicy_Reliability::QOS_eQOSPolicy_Reliability_best_effort_reliability_qos) - { - qos_string += "Best effort"; - } - } - return qos_string; - } else if (column == Columns::TLAYER) { QList layers; @@ -209,7 +147,7 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const } else if (column == Columns::TDESC) { - const std::string& raw_data = topic_.tdesc(); + const std::string& raw_data = topic_.tdatatype().desc(); if (!raw_data.empty()) { @@ -239,25 +177,25 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const for (const auto& layer : layer_pb) { QString this_layer_string; - switch (layer.type()) + if (layer.active()) { - case eCAL::pb::eTLayerType::tl_ecal_tcp: - this_layer_string = "tcp"; - break; - case eCAL::pb::eTLayerType::tl_ecal_udp_mc: - this_layer_string = "udp_mc"; - break; - case eCAL::pb::eTLayerType::tl_ecal_shm: - this_layer_string = "shm"; - break; - case eCAL::pb::eTLayerType::tl_inproc: - this_layer_string = "inproc"; - break; - case eCAL::pb::eTLayerType::tl_all: - this_layer_string = "all"; - break; - default: - this_layer_string = ("Unknown (" + QString::number((int)layer.type()) + ")"); + switch (layer.type()) + { + case eCAL::pb::eTLayerType::tl_ecal_tcp: + this_layer_string = "tcp"; + break; + case eCAL::pb::eTLayerType::tl_ecal_udp_mc: + this_layer_string = "udp_mc"; + break; + case eCAL::pb::eTLayerType::tl_ecal_shm: + this_layer_string = "shm"; + break; + case eCAL::pb::eTLayerType::tl_all: + this_layer_string = "all"; + break; + default: + this_layer_string = ("Unknown (" + QString::number((int)layer.type()) + ")"); + } } if (!layer_string.isEmpty() && !this_layer_string.isEmpty()) @@ -286,7 +224,7 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const { if (column == Columns::TDESC) { - const std::string& raw_data = topic_.tdesc(); + const std::string& raw_data = topic_.tdatatype().desc(); return static_cast(raw_data.size()); } @@ -296,7 +234,7 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const else if (role == (Qt::ItemDataRole)ItemDataRoles::FilterRole) //-V1016 //-V547 { if ((column == Columns::HNAME) - || (column == Columns::HGNAME) + || (column == Columns::SHM_TRANSPORT_DOMAIN) || (column == Columns::PNAME) || (column == Columns::UNAME) || (column == Columns::TNAME) @@ -361,7 +299,7 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const { if ((column == Columns::HNAME) - || (column == Columns::HGNAME) + || (column == Columns::SHM_TRANSPORT_DOMAIN) || (column == Columns::PNAME) || (column == Columns::UNAME) || (column == Columns::TNAME) @@ -379,7 +317,7 @@ QVariant TopicTreeItem::data(Columns column, Qt::ItemDataRole role) const } else if (column == Columns::TDESC) { - const std::string& raw_data = topic_.tdesc(); + const std::string& raw_data = topic_.tdatatype().desc(); if (raw_data.empty()) { QFont font; diff --git a/app/mon/mon_gui/src/widgets/models/topic_tree_item.h b/app/mon/mon_gui/src/widgets/models/topic_tree_item.h index 46713e7054..6661d7710d 100644 --- a/app/mon/mon_gui/src/widgets/models/topic_tree_item.h +++ b/app/mon/mon_gui/src/widgets/models/topic_tree_item.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,7 @@ class TopicTreeItem : { RCLOCK, HNAME, - HGNAME, + SHM_TRANSPORT_DOMAIN, PID, PNAME, UNAME, @@ -49,7 +49,6 @@ class TopicTreeItem : TENCODING, TTYPE, TDESC, - TQOS, TLAYER, TSIZE, CONNECTIONS_LOC, diff --git a/app/mon/mon_gui/src/widgets/models/topic_tree_model.h b/app/mon/mon_gui/src/widgets/models/topic_tree_model.h index 5496bd4454..afb474c55f 100644 --- a/app/mon/mon_gui/src/widgets/models/topic_tree_model.h +++ b/app/mon/mon_gui/src/widgets/models/topic_tree_model.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,14 +51,13 @@ class TopicTreeModel : public GroupTreeModel DIRECTION, UNIT_NAME, HOST_NAME, - HOST_GROUP_NAME, + SHM_TRANSPORT_DOMAIN, PID, PROCESS_NAME, - MESSAGE_TYPE, + TOPIC_TYPE, HEARTBEAT, TOPIC_ENCODING, TOPIC_DESCRIPTOR, - QOS, TRANSPORT_LAYER, TOPIC_SIZE, CONNECTIONS_LOCAL, @@ -91,7 +90,7 @@ class TopicTreeModel : public GroupTreeModel { Columns::GROUP, "Group" }, { Columns::HEARTBEAT, "Heartbeat" }, { Columns::HOST_NAME, "Host" }, - { Columns::HOST_GROUP_NAME, "Host Group" }, + { Columns::SHM_TRANSPORT_DOMAIN, "SHM Transport Domain" }, { Columns::PID, "PID" }, { Columns::PROCESS_NAME, "Process Path" }, { Columns::UNIT_NAME, "Process" }, @@ -99,9 +98,8 @@ class TopicTreeModel : public GroupTreeModel { Columns::TOPIC_NAME, "Topic" }, { Columns::DIRECTION, "Direction" }, { Columns::TOPIC_ENCODING, "Encoding" }, - { Columns::MESSAGE_TYPE, "Message Type" }, + { Columns::TOPIC_TYPE, "Topic Type" }, { Columns::TOPIC_DESCRIPTOR, "Descriptor" }, - { Columns::QOS, "QoS" }, { Columns::TRANSPORT_LAYER, "Layer" }, { Columns::TOPIC_SIZE, "Size [Byte]" }, { Columns::CONNECTIONS_LOCAL, "Loc. Connections" }, @@ -116,7 +114,7 @@ class TopicTreeModel : public GroupTreeModel { Columns::GROUP, -1 }, { Columns::HEARTBEAT, (int)TopicTreeItem::Columns::RCLOCK }, { Columns::HOST_NAME, (int)TopicTreeItem::Columns::HNAME }, - { Columns::HOST_GROUP_NAME, (int)TopicTreeItem::Columns::HGNAME }, + { Columns::SHM_TRANSPORT_DOMAIN, (int)TopicTreeItem::Columns::SHM_TRANSPORT_DOMAIN }, { Columns::PID, (int)TopicTreeItem::Columns::PID }, { Columns::PROCESS_NAME, (int)TopicTreeItem::Columns::PNAME }, { Columns::UNIT_NAME, (int)TopicTreeItem::Columns::UNAME }, @@ -124,9 +122,8 @@ class TopicTreeModel : public GroupTreeModel { Columns::TOPIC_NAME, (int)TopicTreeItem::Columns::TNAME }, { Columns::DIRECTION, (int)TopicTreeItem::Columns::DIRECTION }, { Columns::TOPIC_ENCODING, (int)TopicTreeItem::Columns::TENCODING }, - { Columns::MESSAGE_TYPE, (int)TopicTreeItem::Columns::TTYPE }, + { Columns::TOPIC_TYPE, (int)TopicTreeItem::Columns::TTYPE }, { Columns::TOPIC_DESCRIPTOR, (int)TopicTreeItem::Columns::TDESC }, - { Columns::QOS, (int)TopicTreeItem::Columns::TQOS }, { Columns::TRANSPORT_LAYER, (int)TopicTreeItem::Columns::TLAYER }, { Columns::TOPIC_SIZE, (int)TopicTreeItem::Columns::TSIZE }, { Columns::CONNECTIONS_LOCAL, (int)TopicTreeItem::Columns::CONNECTIONS_LOC }, diff --git a/app/mon/mon_gui/src/widgets/visualisation_widget/visualisation_widget.cpp b/app/mon/mon_gui/src/widgets/visualisation_widget/visualisation_widget.cpp index 51a1301284..3a9a4c8326 100644 --- a/app/mon/mon_gui/src/widgets/visualisation_widget/visualisation_widget.cpp +++ b/app/mon/mon_gui/src/widgets/visualisation_widget/visualisation_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -221,6 +221,6 @@ void VisualisationWidget::checkForMorePublishersWithSameTopic(const eCAL::pb::Mo } } ui_.textEdit->clear(); - for (auto publisher : publishers) + for (const auto& publisher : publishers) ui_.textEdit->append(publisher); } diff --git a/app/mon/mon_plugin_lib/include/ecal/mon/plugin_widget_interface.h b/app/mon/mon_plugin_lib/include/ecal/mon/plugin_widget_interface.h index 0d62bd8e7b..65cf7f4ed3 100644 --- a/app/mon/mon_plugin_lib/include/ecal/mon/plugin_widget_interface.h +++ b/app/mon/mon_plugin_lib/include/ecal/mon/plugin_widget_interface.h @@ -22,7 +22,7 @@ #include #include -#include +#include namespace eCAL { diff --git a/app/mon/mon_plugins/capnproto_reflection/CMakeLists.txt b/app/mon/mon_plugins/capnproto_reflection/CMakeLists.txt index f948a3ac5b..6c0edfac76 100644 --- a/app/mon/mon_plugins/capnproto_reflection/CMakeLists.txt +++ b/app/mon/mon_plugins/capnproto_reflection/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -58,15 +58,17 @@ ecal_add_mon_plugin(${PROJECT_NAME} METADATA src/metadata.json ) -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets - eCAL::core + eCAL::capnproto_core CapnProto::capnp CustomQt eCAL::mon_plugin_lib MonitorTreeView ) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) + target_link_options(${PROJECT_NAME} PRIVATE $<$:/ignore:4099>) target_include_directories(${PROJECT_NAME} PRIVATE src) diff --git a/app/mon/mon_plugins/capnproto_reflection/src/plugin_widget.cpp b/app/mon/mon_plugins/capnproto_reflection/src/plugin_widget.cpp index 77dd0f0124..a5a68b2242 100644 --- a/app/mon/mon_plugins/capnproto_reflection/src/plugin_widget.cpp +++ b/app/mon/mon_plugins/capnproto_reflection/src/plugin_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,8 +58,8 @@ PluginWidget::PluginWidget(const QString& topic_name, const QString& topic_type, ui_.publish_timestamp_warning_label->setVisible(false); // Add eCAL Callbacks - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); - //subscriber_.AddErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); // Button connections connect(ui_.expand_button, &QPushButton::clicked, [this]() { tree_view_->expandAll(); }); @@ -102,8 +102,8 @@ PluginWidget::~PluginWidget() noexcept qDebug().nospace() << "[" << metaObject()->className() << "]: Deleting Widget for topic " << topic_name_; #endif // NDEBUG - subscriber_.RemReceiveCallback(); - //subscriber_.RemErrorCallback(); + subscriber_.RemoveReceiveCallback(); + //subscriber_.RemoveErrorCallback(); { std::lock_guard lock(capnproto_message_mutex_); @@ -208,7 +208,7 @@ void PluginWidget::updateTree() // tree view and replace it with a dummy error-item. We also log an eCAL // error message. - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_error, "Error when receiving data on topic \"" + topic_name_.toStdString() + "\": " + last_error_string_.toStdString()); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_error, "Error when receiving data on topic \"" + topic_name_.toStdString() + "\": " + last_error_string_.toStdString()); tree_model_->removeAllChildren(); currently_showing_error_item_ = true; @@ -322,14 +322,14 @@ void PluginWidget::onUpdate() void PluginWidget::onResume() { // Add eCAL Callbacks - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); - //subscriber_.AddErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); } void PluginWidget::onPause() { - subscriber_.RemReceiveCallback(); - //subscriber_.RemErrorCallback(); + subscriber_.RemoveReceiveCallback(); + subscriber_.RemoveErrorCallback(); } QWidget* PluginWidget::getWidget() diff --git a/app/mon/mon_plugins/monitor_tree_view/CMakeLists.txt b/app/mon/mon_plugins/monitor_tree_view/CMakeLists.txt index bd2f1c99a2..2e86602c2c 100644 --- a/app/mon/mon_plugins/monitor_tree_view/CMakeLists.txt +++ b/app/mon/mon_plugins/monitor_tree_view/CMakeLists.txt @@ -18,6 +18,8 @@ project(MonitorTreeView) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + # Legacy Qt5 (pre 5.15) support as suggested by teh Qt Documentation: # https://doc.qt.io/qt-6/cmake-qt5-and-qt6-compatibility.html#supporting-older-qt-5-versions find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Widgets) diff --git a/app/mon/mon_plugins/plugin_template/CMakeLists.txt b/app/mon/mon_plugins/plugin_template/CMakeLists.txt index dd22d88b7e..24cfb9d869 100644 --- a/app/mon/mon_plugins/plugin_template/CMakeLists.txt +++ b/app/mon/mon_plugins/plugin_template/CMakeLists.txt @@ -43,7 +43,7 @@ ecal_add_mon_plugin(${PROJECT_NAME} METADATA src/metadata.json ) -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets eCAL::core diff --git a/app/mon/mon_plugins/protobuf_reflection/CMakeLists.txt b/app/mon/mon_plugins/protobuf_reflection/CMakeLists.txt index bdc373ce39..36614267a3 100644 --- a/app/mon/mon_plugins/protobuf_reflection/CMakeLists.txt +++ b/app/mon/mon_plugins/protobuf_reflection/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -60,16 +60,16 @@ ecal_add_mon_plugin(${PROJECT_NAME} ) create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets - eCAL::core + eCAL::protobuf_core eCAL::app_pb protobuf::libprotobuf MonitorTreeView eCAL::mon_plugin_lib ) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) if(MSVC) set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4127 /wd4714") diff --git a/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.cpp b/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.cpp index d7a2201c36..f327ef0745 100644 --- a/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.cpp +++ b/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,8 +59,8 @@ PluginWidget::PluginWidget(const QString& topic_name, const QString& topic_type, ui_.publish_timestamp_warning_label->setVisible(false); // Add eCAL Callbacks - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); - subscriber_.AddErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); // Button connections connect(ui_.expand_button, &QPushButton::clicked, [this]() { tree_view_->expandAll(); }); @@ -105,12 +105,12 @@ PluginWidget::~PluginWidget() qDebug().nospace() << "[" << PluginWidget::metaObject()->className() << "]: Deleting Widget for topic " << topic_name_; #endif // NDEBUG - subscriber_.RemReceiveCallback(); - subscriber_.RemErrorCallback(); + subscriber_.RemoveReceiveCallback(); + subscriber_.RemoveErrorCallback(); { std::lock_guard lock(proto_message_mutex_); - delete last_proto_message_; + last_proto_message_.reset(); } } @@ -157,19 +157,15 @@ void PluginWidget::updatePublishTimeLabel() //////////////////////////////////////////////////////////////////////////////// // eCAL Callback -void PluginWidget::onProtoMessageCallback(const google::protobuf::Message& message, long long send_time_usecs) +void PluginWidget::onProtoMessageCallback(const std::shared_ptr& message, long long send_time_usecs) { { // Lock the mutex std::lock_guard lock(proto_message_mutex_); - // Delete the old message - delete last_proto_message_; - // Create a copy of the new message as member variable. We cannot use a reference here, as this may cause a deadlock with the GUI thread - last_proto_message_ = message.New(); - last_proto_message_->CopyFrom(message); + last_proto_message_ = message; last_message_publish_timestamp_ = eCAL::Time::ecal_clock::time_point(std::chrono::duration_cast(std::chrono::microseconds(send_time_usecs))); @@ -210,7 +206,7 @@ void PluginWidget::updateTree() // tree view and replace it with a dummy error-item. We also log an eCAL // error message. - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_error, "Error when receiving data on topic \"" + topic_name_.toStdString() + "\": " + last_error_string_.toStdString()); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_error, "Error when receiving data on topic \"" + topic_name_.toStdString() + "\": " + last_error_string_.toStdString()); tree_model_->removeAllChildren(); currently_showing_error_item_ = true; @@ -323,14 +319,14 @@ void PluginWidget::onUpdate() void PluginWidget::onResume() { // Add eCAL Callbacks - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); - subscriber_.AddErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); } void PluginWidget::onPause() { - subscriber_.RemReceiveCallback(); - subscriber_.RemErrorCallback(); + subscriber_.RemoveReceiveCallback(); + subscriber_.RemoveErrorCallback(); } QWidget* PluginWidget::getWidget() diff --git a/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.h b/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.h index dead5b5ec1..2ebbff3ed9 100644 --- a/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.h +++ b/app/mon/mon_plugins/protobuf_reflection/src/plugin_widget.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ #include "ui_plugin_widget.h" -#include +#include #include class PluginWidget : public QWidget, public eCAL::mon::PluginWidgetInterface @@ -68,11 +68,11 @@ private slots: eCAL::protobuf::CProtoDecoder protobuf_decoder; std::shared_ptr protobuf_tree_builder; - std::mutex proto_message_mutex_; - google::protobuf::Message* last_proto_message_; - eCAL::Time::ecal_clock::time_point last_message_publish_timestamp_; - QString last_error_string_; - bool last_message_was_error_; + std::mutex proto_message_mutex_; + std::shared_ptr last_proto_message_; + eCAL::Time::ecal_clock::time_point last_message_publish_timestamp_; + QString last_error_string_; + bool last_message_was_error_; bool currently_showing_error_item_; int error_counter_; @@ -83,7 +83,7 @@ private slots: bool new_msg_available_; int received_message_counter_; - void onProtoMessageCallback(const google::protobuf::Message& message, long long send_time_usecs); + void onProtoMessageCallback(const std::shared_ptr& message, long long send_time_usecs); void onProtoErrorCallback(const std::string& error); void updatePublishTimeLabel(); diff --git a/app/mon/mon_plugins/protobuf_reflection/src/protobuf_tree_builder.h b/app/mon/mon_plugins/protobuf_reflection/src/protobuf_tree_builder.h index 15055fae46..c3e9fc96b6 100644 --- a/app/mon/mon_plugins/protobuf_reflection/src/protobuf_tree_builder.h +++ b/app/mon/mon_plugins/protobuf_reflection/src/protobuf_tree_builder.h @@ -22,7 +22,7 @@ #include #include "monitor_tree_model.h" -#include +#include #include class ProtobufTreeBuilder : public eCAL::protobuf::MessageVisitor diff --git a/app/mon/mon_plugins/raw_data_reflection/CMakeLists.txt b/app/mon/mon_plugins/raw_data_reflection/CMakeLists.txt index 20c0deca9a..396ac96bb5 100644 --- a/app/mon/mon_plugins/raw_data_reflection/CMakeLists.txt +++ b/app/mon/mon_plugins/raw_data_reflection/CMakeLists.txt @@ -55,7 +55,7 @@ ecal_add_mon_plugin(${PROJECT_NAME} ) create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets eCAL::core diff --git a/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.cpp b/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.cpp index 31c3d1afb3..523db09232 100644 --- a/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.cpp +++ b/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,20 +59,25 @@ PluginWidget::PluginWidget(const QString& topic_name, const QString&, QWidget* p ui_.content_layout->addWidget(frame); // Connect the eCAL Subscriber - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::ecalMessageReceivedCallback, this, std::placeholders::_2)); + subscriber_.SetReceiveCallback([this](const eCAL::STopicId& /*topic_id*/, + const eCAL::SDataTypeInformation& /*data_type_info*/, + const eCAL::SReceiveCallbackData& callback_data) + { + ecalMessageReceivedCallback(callback_data); + }); } PluginWidget::~PluginWidget() { - subscriber_.RemReceiveCallback(); + subscriber_.RemoveReceiveCallback(); } -void PluginWidget::ecalMessageReceivedCallback(const struct eCAL::SReceiveCallbackData* callback_data) +void PluginWidget::ecalMessageReceivedCallback(const eCAL::SReceiveCallbackData& callback_data) { std::lock_guard message_lock(message_mutex_); - last_message_ = QByteArray(static_cast(callback_data->buf), callback_data->size); + last_message_ = QByteArray(static_cast(callback_data.buf), callback_data.size); - last_message_publish_timestamp_ = eCAL::Time::ecal_clock::time_point(std::chrono::microseconds(callback_data->time)); + last_message_publish_timestamp_ = eCAL::Time::ecal_clock::time_point(std::chrono::microseconds(callback_data.time)); received_message_counter_++; new_msg_available_ = true; @@ -128,12 +133,18 @@ void PluginWidget::onUpdate() void PluginWidget::onResume() { - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::ecalMessageReceivedCallback, this, std::placeholders::_2)); + // (Re)Connect the eCAL Subscriber + subscriber_.SetReceiveCallback([this](const eCAL::STopicId& /*topic_id*/, + const eCAL::SDataTypeInformation& /*data_type_info*/, + const eCAL::SReceiveCallbackData& callback_data) + { + ecalMessageReceivedCallback(callback_data); + }); } void PluginWidget::onPause() { - subscriber_.RemReceiveCallback(); + subscriber_.RemoveReceiveCallback(); } void PluginWidget::updateRawMessageView() diff --git a/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.h b/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.h index d2491849d4..72bd872525 100644 --- a/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.h +++ b/app/mon/mon_plugins/raw_data_reflection/src/plugin_widget.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,7 +63,7 @@ private slots: bool new_msg_available_; int received_message_counter_; - void ecalMessageReceivedCallback(const struct eCAL::SReceiveCallbackData* callback_data); + void ecalMessageReceivedCallback(const eCAL::SReceiveCallbackData& callback_data); #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) static QString bytesToHex(const QByteArray& byte_array, char separator = '\0'); diff --git a/app/mon/mon_plugins/signals_plotting/CMakeLists.txt b/app/mon/mon_plugins/signals_plotting/CMakeLists.txt index 69daf94a71..6d6f0f0c96 100644 --- a/app/mon/mon_plugins/signals_plotting/CMakeLists.txt +++ b/app/mon/mon_plugins/signals_plotting/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -72,10 +72,11 @@ ecal_add_mon_plugin(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets eCAL::core + eCAL::protobuf_core eCAL::app_pb protobuf::libprotobuf eCAL::mon_plugin_lib @@ -83,7 +84,7 @@ target_link_libraries (${PROJECT_NAME} CustomQt ) -target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) +target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) if(MSVC) set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4127 /wd4714" ) @@ -91,8 +92,7 @@ endif(MSVC) target_include_directories(${PROJECT_NAME} PRIVATE src) -target_include_directories(${PROJECT_NAME} PRIVATE $) -target_compile_definitions(${PROJECT_NAME} PRIVATE QWT_DLL) +target_include_directories(${PROJECT_NAME} PRIVATE $) ecal_install_mon_plugin(${PROJECT_NAME}) diff --git a/app/mon/mon_plugins/signals_plotting/src/plugin_widget.cpp b/app/mon/mon_plugins/signals_plotting/src/plugin_widget.cpp index 80f8347b47..2e44d02205 100644 --- a/app/mon/mon_plugins/signals_plotting/src/plugin_widget.cpp +++ b/app/mon/mon_plugins/signals_plotting/src/plugin_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,8 +73,8 @@ PluginWidget::PluginWidget(const QString& topic_name, const QString& topic_type, ui_.publish_timestamp_warning_label->setVisible(false); // Add eCAL Callbacks - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); - subscriber_.AddErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::onProtoMessageCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetErrorCallback(std::bind(&PluginWidget::onProtoErrorCallback, this, std::placeholders::_1)); // Button connections connect(ui_.expand_button, &QPushButton::clicked, [this]() { tree_view_->expandAll(); }); @@ -127,12 +127,12 @@ PluginWidget::~PluginWidget() qDebug().nospace() << "[" << PluginWidget::metaObject()->className() << "]: Deleting Widget for topic " << topic_name_; #endif // NDEBUG - subscriber_.RemReceiveCallback(); - subscriber_.RemErrorCallback(); + subscriber_.RemoveReceiveCallback(); + subscriber_.RemoveErrorCallback(); { std::lock_guard lock(proto_message_mutex_); - delete last_proto_message_; + last_proto_message_.reset(); } } @@ -256,19 +256,15 @@ void PluginWidget::setVisibleSplitterHandle(bool state) //////////////////////////////////////////////////////////////////////////////// // eCAL Callback -void PluginWidget::onProtoMessageCallback(const google::protobuf::Message& message, long long send_time_usecs) +void PluginWidget::onProtoMessageCallback(const std::shared_ptr& message, long long send_time_usecs) { { // Lock the mutex std::lock_guard lock(proto_message_mutex_); - // Delete the old message - delete last_proto_message_; - // Create a copy of the new message as member variable. We cannot use a reference here, as this may cause a deadlock with the GUI thread - last_proto_message_ = message.New(); - last_proto_message_->CopyFrom(message); + last_proto_message_ = message; last_message_publish_timestamp_ = eCAL::Time::ecal_clock::time_point(std::chrono::duration_cast(std::chrono::microseconds(send_time_usecs))); @@ -327,7 +323,7 @@ void PluginWidget::updateTree() void PluginWidget::showErrorMessage() { - eCAL::Logging::Log(eCAL_Logging_eLogLevel::log_level_error, "Error when receiving data on topic \"" + topic_name_.toStdString() + "\": " + last_error_string_.toStdString()); + eCAL::Logging::Log(eCAL::Logging::eLogLevel::log_level_error, "Error when receiving data on topic \"" + topic_name_.toStdString() + "\": " + last_error_string_.toStdString()); tree_model_->removeAllChildren(); tree_view_->setVisible(false); diff --git a/app/mon/mon_plugins/signals_plotting/src/plugin_widget.h b/app/mon/mon_plugins/signals_plotting/src/plugin_widget.h index 6b3b92df4a..27ce7c290a 100644 --- a/app/mon/mon_plugins/signals_plotting/src/plugin_widget.h +++ b/app/mon/mon_plugins/signals_plotting/src/plugin_widget.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ #include "ui_plugin_widget.h" -#include +#include #include class PluginWidget : public QWidget, public eCAL::mon::PluginWidgetInterface @@ -102,9 +102,9 @@ private slots: eCAL::protobuf::CProtoDecoder protobuf_decoder; std::shared_ptr protobuf_tree_builder; - std::mutex proto_message_mutex_; - google::protobuf::Message* last_proto_message_; - eCAL::Time::ecal_clock::time_point last_message_publish_timestamp_; + std::mutex proto_message_mutex_; + std::shared_ptr last_proto_message_; + eCAL::Time::ecal_clock::time_point last_message_publish_timestamp_; QString last_error_string_; bool last_message_was_error_; int error_counter_; @@ -119,7 +119,7 @@ private slots: QString key_to_close_; - void onProtoMessageCallback(const google::protobuf::Message& message, long long send_time_usecs); + void onProtoMessageCallback(const std::shared_ptr& message, long long send_time_usecs); void onProtoErrorCallback(const std::string& error); void updatePublishTimeLabel(); bool find_items(QAbstractTreeItem* tree_item); diff --git a/app/mon/mon_plugins/signals_plotting/src/protobuf_tree_builder.h b/app/mon/mon_plugins/signals_plotting/src/protobuf_tree_builder.h index 60d4ed9a89..eaba487264 100644 --- a/app/mon/mon_plugins/signals_plotting/src/protobuf_tree_builder.h +++ b/app/mon/mon_plugins/signals_plotting/src/protobuf_tree_builder.h @@ -22,7 +22,7 @@ #include #include "signal_tree_model.h" -#include +#include #include class ProtobufTreeBuilder : public eCAL::protobuf::MessageVisitor diff --git a/app/mon/mon_plugins/string_reflection/CMakeLists.txt b/app/mon/mon_plugins/string_reflection/CMakeLists.txt index 836200ec19..98c672d291 100644 --- a/app/mon/mon_plugins/string_reflection/CMakeLists.txt +++ b/app/mon/mon_plugins/string_reflection/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,10 +55,10 @@ ecal_add_mon_plugin(${PROJECT_NAME} ) create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets - eCAL::core + eCAL::string_core eCAL::mon_plugin_lib ) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) diff --git a/app/mon/mon_plugins/string_reflection/src/plugin_widget.cpp b/app/mon/mon_plugins/string_reflection/src/plugin_widget.cpp index 69b1bbe664..7a1c22e3fe 100644 --- a/app/mon/mon_plugins/string_reflection/src/plugin_widget.cpp +++ b/app/mon/mon_plugins/string_reflection/src/plugin_widget.cpp @@ -46,12 +46,12 @@ PluginWidget::PluginWidget(const QString& topic_name, const QString&, QWidget* p ui_.content_layout->addWidget(text_edit_); // Connect the eCAL Subscriber - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::ecalMessageReceivedCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::ecalMessageReceivedCallback, this, std::placeholders::_2, std::placeholders::_3)); } PluginWidget::~PluginWidget() { - subscriber_.RemReceiveCallback(); + subscriber_.RemoveReceiveCallback(); } void PluginWidget::ecalMessageReceivedCallback(const std::string& message, long long publish_timestamp_usecs) @@ -115,12 +115,12 @@ void PluginWidget::onUpdate() void PluginWidget::onResume() { - subscriber_.AddReceiveCallback(std::bind(&PluginWidget::ecalMessageReceivedCallback, this, std::placeholders::_2, std::placeholders::_3)); + subscriber_.SetReceiveCallback(std::bind(&PluginWidget::ecalMessageReceivedCallback, this, std::placeholders::_2, std::placeholders::_3)); } void PluginWidget::onPause() { - subscriber_.RemReceiveCallback(); + subscriber_.RemoveReceiveCallback(); } void PluginWidget::updateStringMessageView() diff --git a/app/mon/mon_plugins/string_reflection/src/plugin_widget.h b/app/mon/mon_plugins/string_reflection/src/plugin_widget.h index ae99943f77..f09c455b1f 100644 --- a/app/mon/mon_plugins/string_reflection/src/plugin_widget.h +++ b/app/mon/mon_plugins/string_reflection/src/plugin_widget.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,12 +56,12 @@ private slots: QTextEdit* text_edit_; eCAL::string::CSubscriber subscriber_; - std::string last_message_; - eCAL::Time::ecal_clock::time_point last_message_publish_timestamp_; - std::mutex message_mutex_; + std::string last_message_; + eCAL::Time::ecal_clock::time_point last_message_publish_timestamp_; + std::mutex message_mutex_; - bool new_msg_available_; - int received_message_counter_; + bool new_msg_available_; + int received_message_counter_; void ecalMessageReceivedCallback(const std::string& message, long long publish_timestamp_usecs); }; diff --git a/app/mon/mon_tui/CMakeLists.txt b/app/mon/mon_tui/CMakeLists.txt index 1f3311c2d0..24208ac2a3 100644 --- a/app/mon/mon_tui/CMakeLists.txt +++ b/app/mon/mon_tui/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -115,10 +115,11 @@ target_compile_definitions(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE protobuf::libprotobuf tclap::tclap - eCAL::core + eCAL::protobuf_core + eCAL::string_core eCAL::core_pb ftxui::screen ftxui::dom diff --git a/app/mon/mon_tui/src/main.cpp b/app/mon/mon_tui/src/main.cpp index ec360131ca..6dc92442ca 100644 --- a/app/mon/mon_tui/src/main.cpp +++ b/app/mon/mon_tui/src/main.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,10 +32,12 @@ int main(int argc, char** argv) { auto args = ParseArgs(argc, argv); - auto status = eCAL::Initialize(0, nullptr, "eCALMon TUI", eCAL::Init::Default | eCAL::Init::Monitoring); - if (status == -1) std::cerr << "Failed to init" << std::endl; - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); - eCAL::Monitoring::SetFilterState(false); + auto config = eCAL::Init::Configuration(); + config.logging.receiver.enable = true; + + auto status = eCAL::Initialize(config, "eCALMon TUI", eCAL::Init::Default | eCAL::Init::Monitoring); + if (status == false) std::cerr << "Failed to init" << std::endl; + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); TUI::Start(args); diff --git a/app/mon/mon_tui/src/model/data/process.hpp b/app/mon/mon_tui/src/model/data/process.hpp index 5adcaf0b20..bb3dba80c0 100644 --- a/app/mon/mon_tui/src/model/data/process.hpp +++ b/app/mon/mon_tui/src/model/data/process.hpp @@ -43,11 +43,6 @@ struct Process std::string host_name; std::string unit_name; std::string params; - int64_t memory_usage; - float cpu_usage; - float user_time; - int64_t data_sent_bytes; - int64_t data_recieved_bytes; Severity severity; SeverityLevel severity_level; std::string state_info; diff --git a/app/mon/mon_tui/src/model/data/topic.hpp b/app/mon/mon_tui/src/model/data/topic.hpp index 91c6c1f026..5486301baf 100644 --- a/app/mon/mon_tui/src/model/data/topic.hpp +++ b/app/mon/mon_tui/src/model/data/topic.hpp @@ -25,19 +25,9 @@ struct Topic { - enum class QOSReliability - { - BEST_EFFORT, RELIABLE - }; - - enum class QOSHistoryKind - { - KEEP_LAST, KEEP_ALL - }; - enum class TransportLayer { - NONE, UDP_MC, SHM, TCP, INPROC, ALL + NONE, UDP_MC, SHM, TCP, ALL }; enum class Direction @@ -46,7 +36,6 @@ struct Topic }; int32_t registration_clock; - int32_t host_id; std::string host_name; int32_t pid; std::string process_name; @@ -54,11 +43,9 @@ struct Topic std::string id; std::string name; Direction direction; + std::string encoding; std::string type; std::string type_descriptor; - QOSHistoryKind history_kind; - int32_t history_depth; - QOSReliability reliability; std::vector transport_layers; int32_t size; int32_t local_connections_count; diff --git a/app/mon/mon_tui/src/model/log.hpp b/app/mon/mon_tui/src/model/log.hpp index 52bac02dad..0bdebdec77 100644 --- a/app/mon/mon_tui/src/model/log.hpp +++ b/app/mon/mon_tui/src/model/log.hpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ #ifdef _MSC_VER #pragma warning(push, 0) // disable proto warnings #endif +#include "ecal/core/pb/logging.pb.h" #include "ecal/core/pb/monitoring.pb.h" #ifdef _MSC_VER #pragma warning(pop) @@ -53,7 +54,7 @@ class LogModel bool is_polling; int capacity = 500; - eCAL::pb::Logging logs; + eCAL::pb::LogMessageList logs; std::mutex mtx; std::thread update_thread; @@ -72,21 +73,21 @@ class LogModel { switch (val) { - case eCAL_Logging_eLogLevel::log_level_debug1: + case eCAL::Logging::eLogLevel::log_level_debug1: return LogEntry::Level::DEBUG1; - case eCAL_Logging_eLogLevel::log_level_debug2: + case eCAL::Logging::eLogLevel::log_level_debug2: return LogEntry::Level::DEBUG2; - case eCAL_Logging_eLogLevel::log_level_debug3: + case eCAL::Logging::eLogLevel::log_level_debug3: return LogEntry::Level::DEBUG3; - case eCAL_Logging_eLogLevel::log_level_debug4: + case eCAL::Logging::eLogLevel::log_level_debug4: return LogEntry::Level::DEBUG4; - case eCAL_Logging_eLogLevel::log_level_warning: + case eCAL::Logging::eLogLevel::log_level_warning: return LogEntry::Level::WARNING; - case eCAL_Logging_eLogLevel::log_level_error: + case eCAL::Logging::eLogLevel::log_level_error: return LogEntry::Level::ERROR; - case eCAL_Logging_eLogLevel::log_level_fatal: + case eCAL::Logging::eLogLevel::log_level_fatal: return LogEntry::Level::FATAL; - case eCAL_Logging_eLogLevel::log_level_info: + case eCAL::Logging::eLogLevel::log_level_info: default: return LogEntry::Level::INFO; } @@ -110,10 +111,10 @@ class LogModel { std::lock_guard lock{mtx}; std::string raw_data; - eCAL::Monitoring::GetLogging(raw_data); + eCAL::Logging::GetLogging(raw_data); logs.ParseFromString(raw_data); - auto &pb_logs = logs.logs(); + auto &pb_logs = logs.log_messages(); auto new_entries_count = pb_logs.size(); if(new_entries_count == 0) { @@ -126,7 +127,7 @@ class LogModel { data.erase(data.begin(), data.begin() + overflow_size); } - for(auto &l: logs.logs()) data.push_back(ToLogEntry(l)); + for(auto &l: logs.log_messages()) data.push_back(ToLogEntry(l)); } NotifyUpdate(); diff --git a/app/mon/mon_tui/src/model/monitor.hpp b/app/mon/mon_tui/src/model/monitor.hpp index 8ebca2ce21..009812fae7 100644 --- a/app/mon/mon_tui/src/model/monitor.hpp +++ b/app/mon/mon_tui/src/model/monitor.hpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -120,30 +120,6 @@ class MonitorModel return Topic::Direction::SUBSCRIBER; } - Topic::QOSHistoryKind TopicHistoryKind(eCAL::pb::QOS_eQOSPolicy_HistoryKind kind) - { - switch(kind) - { - case eCAL::pb::QOS_eQOSPolicy_HistoryKind_keep_all_history_qos: - return Topic::QOSHistoryKind::KEEP_ALL; - case eCAL::pb::QOS_eQOSPolicy_HistoryKind_keep_last_history_qos: - default: - return Topic::QOSHistoryKind::KEEP_LAST; - } - } - - Topic::QOSReliability TopicReliability(eCAL::pb::QOS_eQOSPolicy_Reliability reliability) - { - switch(reliability) - { - case eCAL::pb::QOS_eQOSPolicy_Reliability_reliable_reliability_qos: - return Topic::QOSReliability::RELIABLE; - case eCAL::pb::QOS_eQOSPolicy_Reliability_best_effort_reliability_qos: - default: - return Topic::QOSReliability::BEST_EFFORT; - } - } - Topic::TransportLayer TopicTransportLayer(eCAL::pb::eTLayerType layer) { switch(layer) @@ -156,8 +132,6 @@ class MonitorModel return Topic::TransportLayer::TCP; case eCAL::pb::tl_ecal_udp_mc: return Topic::TransportLayer::UDP_MC; - case eCAL::pb::tl_inproc: - return Topic::TransportLayer::INPROC; case eCAL::pb::tl_none: default: return Topic::TransportLayer::NONE; @@ -188,11 +162,6 @@ class MonitorModel process.host_name = std::move(*p.mutable_hname()); process.unit_name = std::move(*p.mutable_uname()); process.params = std::move(*p.mutable_pparam()); - process.memory_usage = p.pmemory(); - process.cpu_usage = p.pcpu();; - process.user_time = p.usrptime(); - process.data_sent_bytes = p.datawrite(); - process.data_recieved_bytes = p.dataread(); process.severity = Severity(p.state().severity()); process.severity_level = SeverityLevel(p.state().severity_level()); process.state_info = std::move(*p.mutable_state()->mutable_info()); @@ -223,7 +192,6 @@ class MonitorModel } auto &topic = topics.emplace_back(); topic.registration_clock = t.rclock(); - topic.host_id = t.hid(); topic.host_name = std::move(*t.mutable_hname()); topic.pid = t.pid(); topic.process_name = std::move(*t.mutable_pname()); @@ -231,14 +199,15 @@ class MonitorModel topic.id = std::move(*t.mutable_tid()); topic.name = std::move(*t.mutable_tname()); topic.direction = TopicDirection(t.direction()); - topic.type = std::move(*t.mutable_ttype()); - topic.type_descriptor = std::move(*t.mutable_tdesc()); - topic.history_kind = TopicHistoryKind(t.tqos().history()); - topic.history_depth = t.tqos().history_depth(); - topic.reliability = TopicReliability(t.tqos().reliability()); + topic.encoding = std::move(*t.mutable_tdatatype()->mutable_encoding()); + topic.type = std::move(*t.mutable_tdatatype()->mutable_name()); + topic.type_descriptor = std::move(*t.mutable_tdatatype()->mutable_desc()); for(auto &tl: t.tlayer()) { - topic.transport_layers.emplace_back(TopicTransportLayer(tl.type())); + if (tl.active()) + { + topic.transport_layers.emplace_back(TopicTransportLayer(tl.type())); + } } topic.size = t.tsize(); topic.local_connections_count = t.connections_loc(); diff --git a/app/mon/mon_tui/src/tui/view/message_visualization/factory.hpp b/app/mon/mon_tui/src/tui/view/message_visualization/factory.hpp index 3e07c58ffd..79c17f14a4 100644 --- a/app/mon/mon_tui/src/tui/view/message_visualization/factory.hpp +++ b/app/mon/mon_tui/src/tui/view/message_visualization/factory.hpp @@ -28,14 +28,14 @@ #include "utils/string.hpp" std::shared_ptr CreateVisualizationView(std::shared_ptr factory, - std::shared_ptr vm_factory, const std::string &topic, const std::string &type_name) + std::shared_ptr vm_factory, const std::string &topic, const std::string &encoding, const std::string &type_name) { - if(type_name == "base:std::string") + if(type_name == "std::string") { auto vm = vm_factory->Create(topic); return factory->Create(vm); } - else if(StartsWith(type_name, "proto:")) + else if(encoding == "proto") { auto vm = vm_factory->Create(topic); return factory->Create(vm); diff --git a/app/mon/mon_tui/src/tui/view/message_visualization/proto_tree.hpp b/app/mon/mon_tui/src/tui/view/message_visualization/proto_tree.hpp index a3274c8008..7d64516496 100644 --- a/app/mon/mon_tui/src/tui/view/message_visualization/proto_tree.hpp +++ b/app/mon/mon_tui/src/tui/view/message_visualization/proto_tree.hpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include #include @@ -261,7 +261,7 @@ class TreeMessageVisitor : public MessageVisitor } -void PopulateProtoTree(ftxui::TreeNode &root, google::protobuf::Message *message, const std::shared_ptr style) +void PopulateProtoTree(ftxui::TreeNode &root, const std::shared_ptr& message, const std::shared_ptr style) { auto tree_builder = std::make_shared(root, style); if(message) @@ -272,7 +272,7 @@ void PopulateProtoTree(ftxui::TreeNode &root, google::protobuf::Message *message } } -ftxui::TreeNodePtr ProtoTree(google::protobuf::Message *message, const std::shared_ptr style) +ftxui::TreeNodePtr ProtoTree(const std::shared_ptr& message, const std::shared_ptr style) { using namespace ftxui; auto root = std::make_shared(); diff --git a/app/mon/mon_tui/src/tui/view/topic_details.hpp b/app/mon/mon_tui/src/tui/view/topic_details.hpp index aeddd87927..518cec18e8 100644 --- a/app/mon/mon_tui/src/tui/view/topic_details.hpp +++ b/app/mon/mon_tui/src/tui/view/topic_details.hpp @@ -57,10 +57,6 @@ class TopicDetailsView : public View separatorEmpty(), text("External connections: " + std::to_string(details->external_connections_count)), separatorEmpty(), - text("QOS - Reliability: " + std::to_string(details->reliability)), - text("QOS - History: " + std::to_string(details->history_kind)), - text("QOS - History depth: " + std::to_string(details->history_depth)), - separatorEmpty(), text("Attributes:"), vbox(attributes) ); @@ -77,13 +73,14 @@ class TopicDetailsView : public View vizualization_view = ftxui::Renderer([]{ return ftxui::emptyElement(); }); } - auto tname = topic->name; - auto ttype = topic->type; + const auto tname = topic->name; + const auto tencoding = topic->encoding; + const auto ttype = topic->type; if(tname != prev_topic) { prev_topic = tname; vizualization_view->Detach(); - vizualization_view = CreateVisualizationView(view_factory, view_model->view_model_factory, tname, ttype); + vizualization_view = CreateVisualizationView(view_factory, view_model->view_model_factory, tname, tencoding, ttype); Add(vizualization_view); } return vizualization_view; diff --git a/app/mon/mon_tui/src/tui/viewmodel/command_line.hpp b/app/mon/mon_tui/src/tui/viewmodel/command_line.hpp index b796bfedbf..84ccd3fc0d 100644 --- a/app/mon/mon_tui/src/tui/viewmodel/command_line.hpp +++ b/app/mon/mon_tui/src/tui/viewmodel/command_line.hpp @@ -19,7 +19,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/app/mon/mon_tui/src/tui/viewmodel/message_visualization/proto.hpp b/app/mon/mon_tui/src/tui/viewmodel/message_visualization/proto.hpp index 0db3abd09a..9eec2b6b26 100644 --- a/app/mon/mon_tui/src/tui/viewmodel/message_visualization/proto.hpp +++ b/app/mon/mon_tui/src/tui/viewmodel/message_visualization/proto.hpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,13 +20,14 @@ #include #include +#include #include #include #include #include -#include +#include #include "tui/viewmodel/message_visualization/message_visualization.hpp" @@ -35,15 +36,13 @@ class ProtoMessageVisualizationViewModel : public MessageVisualizationViewModel eCAL::protobuf::CDynamicSubscriber subscriber; mutable std::mutex message_mtx; - google::protobuf::Message *latest_message = nullptr; + std::shared_ptr latest_message = nullptr; - void OnMessage(const google::protobuf::Message& message, long long send_time_usecs) + void OnMessage(const std::shared_ptr& message, long long send_time_usecs) { { std::lock_guard lock(message_mtx); - delete latest_message; - latest_message = message.New(); - latest_message->CopyFrom(message); + latest_message = message; message_timestamp = send_time_usecs; } @@ -56,7 +55,7 @@ class ProtoMessageVisualizationViewModel : public MessageVisualizationViewModel //NOTE: Use with caution! struct ProtectedMessage { - google::protobuf::Message *message; + std::shared_ptr message; std::unique_lock lock; }; @@ -64,7 +63,7 @@ class ProtoMessageVisualizationViewModel : public MessageVisualizationViewModel : subscriber{topic} { using namespace std::placeholders; - subscriber.AddReceiveCallback(std::bind(&ProtoMessageVisualizationViewModel::OnMessage, this, _2, _3)); + subscriber.SetReceiveCallback(std::bind(&ProtoMessageVisualizationViewModel::OnMessage, this, _2, _3)); } ProtectedMessage message() const diff --git a/app/mon/mon_tui/src/tui/viewmodel/message_visualization/raw.hpp b/app/mon/mon_tui/src/tui/viewmodel/message_visualization/raw.hpp index 1dcf1aea55..c6879e27b5 100644 --- a/app/mon/mon_tui/src/tui/viewmodel/message_visualization/raw.hpp +++ b/app/mon/mon_tui/src/tui/viewmodel/message_visualization/raw.hpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,12 +36,12 @@ class RawMessageVisualizationViewModel : public MessageVisualizationViewModel mutable std::mutex message_mtx; std::string latest_message; - void OnMessage(const struct eCAL::SReceiveCallbackData* callback_data) + void OnMessage(const struct eCAL::SReceiveCallbackData& callback_data) { { std::lock_guard lock{message_mtx}; - latest_message = std::string(static_cast(callback_data->buf), callback_data->size); - message_timestamp = callback_data->time; + latest_message = std::string(static_cast(callback_data.buf), callback_data.size); + message_timestamp = callback_data.time; } NotifyDataUpdated(); @@ -52,7 +52,7 @@ class RawMessageVisualizationViewModel : public MessageVisualizationViewModel : subscriber{topic} { using namespace std::placeholders; - subscriber.AddReceiveCallback(std::bind(&RawMessageVisualizationViewModel::OnMessage, this, _2)); + subscriber.SetReceiveCallback(std::bind(&RawMessageVisualizationViewModel::OnMessage, this, _3)); } std::string message() const diff --git a/app/mon/mon_tui/src/tui/viewmodel/message_visualization/string.hpp b/app/mon/mon_tui/src/tui/viewmodel/message_visualization/string.hpp index d3c49fc309..9c1536db38 100644 --- a/app/mon/mon_tui/src/tui/viewmodel/message_visualization/string.hpp +++ b/app/mon/mon_tui/src/tui/viewmodel/message_visualization/string.hpp @@ -51,7 +51,7 @@ class StringMessageVisualizationViewModel : public MessageVisualizationViewModel : subscriber{topic} { using namespace std::placeholders; - subscriber.AddReceiveCallback(std::bind(&StringMessageVisualizationViewModel::OnMessage, this, _2, _3)); + subscriber.SetReceiveCallback(std::bind(&StringMessageVisualizationViewModel::OnMessage, this, _2, _3)); } std::string message() const diff --git a/app/mon/mon_tui/src/tui/viewmodel/processes.hpp b/app/mon/mon_tui/src/tui/viewmodel/processes.hpp index 1ae9587f84..a671d5e26d 100644 --- a/app/mon/mon_tui/src/tui/viewmodel/processes.hpp +++ b/app/mon/mon_tui/src/tui/viewmodel/processes.hpp @@ -29,11 +29,11 @@ class ProcessesViewModel : public TableViewModel public: enum Column { - Host, PID, Name, CPU, Memory, Info, State + Host, PID, Name, Info, State }; ProcessesViewModel(std::shared_ptr model_) - : TableViewModel({"Host", "PID", "Name", "CPU", "Memory", "Info", "State"}) + : TableViewModel({"Host", "PID", "Name", "Info", "State"}) { title = "Processes"; model_->AddModelUpdateCallback([this, model_] { @@ -51,10 +51,6 @@ class ProcessesViewModel : public TableViewModel return std::to_string(value.pid); case Column::Name: return value.name; - case Column::CPU: - return std::to_string(value.cpu_usage); - case Column::Memory: - return std::to_string(value.memory_usage); case Column::Info: return value.state_info; case Column::State: diff --git a/app/mon/mon_tui/src/tui/viewmodel/topics.hpp b/app/mon/mon_tui/src/tui/viewmodel/topics.hpp index 25bffa5101..8c52b8bcd7 100644 --- a/app/mon/mon_tui/src/tui/viewmodel/topics.hpp +++ b/app/mon/mon_tui/src/tui/viewmodel/topics.hpp @@ -32,11 +32,11 @@ class TopicsViewModel : public TableViewModel public: enum Column { - Id, Host, Process, Name, Type, Direction, Layer, Size, DataClock, Frequency + Id, Host, Process, Name, Encoding, Type, Direction, Layer, Size, DataClock, Frequency }; TopicsViewModel(std::shared_ptr model_) - : TableViewModel({"Id", "Host", "Process", "Topic", "Type", "Direction", "Layer", "Size", "DataClock", "Frequency"}) + : TableViewModel({"Id", "Host", "Process", "Topic", "Encoding", "Type", "Direction", "Layer", "Size", "DataClock", "Frequency"}) { title = "Topics"; @@ -60,6 +60,8 @@ class TopicsViewModel : public TableViewModel return value.unit_name; case Column::Name: return value.name; + case Column::Encoding: + return value.encoding; case Column::Type: return value.type; case Column::Direction: diff --git a/app/mon/mon_tui/src/utils/string.hpp b/app/mon/mon_tui/src/utils/string.hpp index adafb4f03a..c57d84cbc7 100644 --- a/app/mon/mon_tui/src/utils/string.hpp +++ b/app/mon/mon_tui/src/utils/string.hpp @@ -128,7 +128,6 @@ std::string to_string(Topic::TransportLayer value) case Topic::TransportLayer::UDP_MC: return "UDP multicast"; case Topic::TransportLayer::SHM: return "SHM"; case Topic::TransportLayer::TCP: return "TCP"; - case Topic::TransportLayer::INPROC: return "InProc"; case Topic::TransportLayer::ALL: return "All"; case Topic::TransportLayer::NONE: default: @@ -157,26 +156,4 @@ std::string to_string(const std::vector &value) return str; } -std::string to_string(Topic::QOSHistoryKind value) -{ - switch(value) - { - case Topic::QOSHistoryKind::KEEP_LAST: return "Keep last"; - case Topic::QOSHistoryKind::KEEP_ALL: - default: - return "Keep all"; - } -} - -std::string to_string(Topic::QOSReliability value) -{ - switch(value) - { - case Topic::QOSReliability::RELIABLE: return "Reliable"; - case Topic::QOSReliability::BEST_EFFORT: - default: - return "Best effort"; - } -} - } diff --git a/app/play/play_cli/CMakeLists.txt b/app/play/play_cli/CMakeLists.txt index 20f36b8707..66afac8ac8 100644 --- a/app/play/play_cli/CMakeLists.txt +++ b/app/play/play_cli/CMakeLists.txt @@ -44,7 +44,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE src) target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:PCRE_STATIC;_UNICODE>) -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE termcolor::termcolor tclap::tclap eCAL::play_core diff --git a/app/play/play_core/CMakeLists.txt b/app/play/play_core/CMakeLists.txt index 466e6ee9e1..b978dcca9c 100644 --- a/app/play/play_core/CMakeLists.txt +++ b/app/play/play_core/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -55,10 +55,10 @@ target_link_libraries(${PROJECT_NAME} PUBLIC Threads::Threads spdlog::spdlog protobuf::libprotobuf - eCAL::core + eCAL::protobuf_core eCAL::app_pb eCAL::ecaltime_pb - eCAL::measurement_hdf5 + eCAL::hdf5 ) target_link_libraries(${PROJECT_NAME} PRIVATE diff --git a/app/play/play_core/include/ecal_play.h b/app/play/play_core/include/ecal_play.h index ad07a767e2..95e8823b9d 100644 --- a/app/play/play_core/include/ecal_play.h +++ b/app/play/play_core/include/ecal_play.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -298,6 +298,15 @@ class EcalPlay **/ std::string GetChannelType(const std::string& channel_name) const; + /** + * @brief Gets the encoding of the given channel + * + * @param channel_name channel name + * + * @return channel type +**/ + std::string GetChannelEncoding(const std::string& channel_name) const; + void CalculateEstimatedSizeForChannels() const; /** diff --git a/app/play/play_core/include/ecal_play_logger.h b/app/play/play_core/include/ecal_play_logger.h index 265746c17e..d9fdbe45c8 100644 --- a/app/play/play_core/include/ecal_play_logger.h +++ b/app/play/play_core/include/ecal_play_logger.h @@ -49,7 +49,7 @@ class EcalPlayLogger static const int MAXIMUM_ROTATING_FILES = 5; static const int FIVE_MEGABYTES = 5 * 1024 * 1024; - auto ecal_data_path = eCAL::Util::GeteCALLogPath(); + auto ecal_data_path = eCAL::Util::GeteCALLogDir(); std::string log_filename = ecal_data_path + EcalPlayGlobals::ECAL_PLAY_NAME + ".log"; // create console logger and rotating file logger with maximum size 5MB and maximum 5 rotating files diff --git a/app/play/play_core/include/ecal_play_scenario.h b/app/play/play_core/include/ecal_play_scenario.h index 3332153a7b..93f9e59731 100644 --- a/app/play/play_core/include/ecal_play_scenario.h +++ b/app/play/play_core/include/ecal_play_scenario.h @@ -22,7 +22,7 @@ #include #include -#include +#include /** * @brief A Scenario is a named time point diff --git a/app/play/play_core/src/ecal_play.cpp b/app/play/play_core/src/ecal_play.cpp index 45d9608688..7dfb4dfb9e 100644 --- a/app/play/play_core/src/ecal_play.cpp +++ b/app/play/play_core/src/ecal_play.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,16 +19,16 @@ #include "ecal_play.h" -#include +#include +#include #include +#include +#include #include -#include -#include #include "ecal_play_logger.h" #include "play_thread.h" -#include - +#include #include #include #include @@ -37,12 +37,12 @@ EcalPlay::EcalPlay() { LogAppNameVersion(); - eCAL::Initialize(0, nullptr, "eCALPlay"); + eCAL::Initialize("eCALPlay"); play_thread_ = std::make_unique(); play_thread_->Start(); - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_warning, eCAL_Process_eSeverity_Level::proc_sev_level1, "No measurement loaded"); + eCAL::Process::SetState(eCAL::Process::eSeverity::warning, eCAL::Process::eSeverityLevel::level1, "No measurement loaded"); } EcalPlay::~EcalPlay() @@ -58,7 +58,7 @@ bool EcalPlay::LoadMeasurement(const std::string& path) { EcalPlayLogger::Instance()->info("Loading measurement..."); - std::shared_ptr measurement(std::make_shared()); + std::shared_ptr measurement(std::make_shared()); std::string meas_dir; // The directory of the measurement std::string path_to_load; // The actual path we load the measurement from. May be a directory or a .hdf5 file @@ -114,14 +114,14 @@ bool EcalPlay::LoadMeasurement(const std::string& path) LoadScenarios(meas_dir + "/doc", meas_dir + "/doc/scenario.txt"); LogMeasurementSummary(); - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_healthy, eCAL_Process_eSeverity_Level::proc_sev_level1, "Measurement loaded"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Measurement loaded"); return true; } else { EcalPlayLogger::Instance()->error("Failed loading measurement from: " + meas_dir); - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_warning, eCAL_Process_eSeverity_Level::proc_sev_level1, "Failed loading measurement"); + eCAL::Process::SetState(eCAL::Process::eSeverity::warning, eCAL::Process::eSeverityLevel::level1, "Failed loading measurement"); return false; } } @@ -129,7 +129,7 @@ bool EcalPlay::LoadMeasurement(const std::string& path) void EcalPlay::CloseMeasurement() { description_ = ""; - play_thread_->SetMeasurement(std::shared_ptr(nullptr)); + play_thread_->SetMeasurement(std::shared_ptr(nullptr)); measurement_path_ = ""; clearScenariosPath(); channel_mapping_path_ = ""; @@ -224,6 +224,11 @@ std::string EcalPlay::GetChannelType(const std::string& channel_name) const return play_thread_->GetChannelType(channel_name); } +std::string EcalPlay::GetChannelEncoding(const std::string& channel_name) const +{ + return play_thread_->GetChannelEncoding(channel_name); +} + void EcalPlay::CalculateEstimatedSizeForChannels() const { play_thread_->CalculateEstimatedSizeForChannels(); diff --git a/app/play/play_core/src/measurement_container.cpp b/app/play/play_core/src/measurement_container.cpp index d95de520b4..a469262fa2 100644 --- a/app/play/play_core/src/measurement_container.cpp +++ b/app/play/play_core/src/measurement_container.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,13 +18,15 @@ */ #include "measurement_container.h" -#include + +#include +#include #include #include #include -MeasurementContainer::MeasurementContainer(std::shared_ptr hdf5_meas, const std::string& meas_dir, bool use_receive_timestamp) +MeasurementContainer::MeasurementContainer(std::shared_ptr hdf5_meas, const std::string& meas_dir, bool use_receive_timestamp) : hdf5_meas_ (hdf5_meas) , meas_dir_ (meas_dir) , use_receive_timestamp_ (use_receive_timestamp) @@ -129,10 +131,12 @@ void MeasurementContainer::CreatePublishers(const std::mapGetChannelType(channel_mapping.first); - auto topic_description = hdf5_meas_->GetChannelDescription(channel_mapping.first); - - publisher_map_.emplace(channel_mapping.first, PublisherInfo(channel_mapping.second, topic_type, topic_description)); + auto topic_info = hdf5_meas_->GetChannelDataTypeInformation(channel_mapping.first); + eCAL::SDataTypeInformation data_type_info; + data_type_info.name = topic_info.name; + data_type_info.encoding = topic_info.encoding; + data_type_info.descriptor = topic_info.descriptor; + publisher_map_.emplace(channel_mapping.first, PublisherInfo(channel_mapping.second, data_type_info)); } // Assign publishers to entries @@ -151,10 +155,6 @@ void MeasurementContainer::CreatePublishers(const std::map GetFrameCount()) + if (!publishers_initialized_ || (index < 0) || index >= GetFrameCount()) return false; if (frame_table_[index].publisher_info_) @@ -215,7 +215,8 @@ bool MeasurementContainer::PublishFrame(long long index) { timestamp_usecs = std::chrono::duration_cast(frame_table_[index].send_timestamp_.time_since_epoch()).count(); } - frame_table_[index].publisher_info_->publisher_.SetID(frame_table_[index].send_id_); + // this is not supported by the eCAL v6 API + //frame_table_[index].publisher_info_->publisher_.SetID(frame_table_[index].send_id_); frame_table_[index].publisher_info_->publisher_.Send(send_buffer_, data_size, timestamp_usecs); frame_table_[index].publisher_info_->message_counter_++; return true; @@ -307,7 +308,12 @@ double MeasurementContainer::GetMaxTimestampOfChannel(const std::string& channel std::string MeasurementContainer::GetChannelType(const std::string& channel_name) const { - return hdf5_meas_->GetChannelType(channel_name); + return hdf5_meas_->GetChannelDataTypeInformation(channel_name).name; +} + +std::string MeasurementContainer::GetChannelEncoding(const std::string& channel_name) const +{ + return hdf5_meas_->GetChannelDataTypeInformation(channel_name).encoding; } size_t MeasurementContainer::GetChannelCumulativeEstimatedSize(const std::string& channel_name) const diff --git a/app/play/play_core/src/measurement_container.h b/app/play/play_core/src/measurement_container.h index 690af019d8..55eed88f1a 100644 --- a/app/play/play_core/src/measurement_container.h +++ b/app/play/play_core/src/measurement_container.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,14 +24,15 @@ #include #include -#include +#include +#include #include "continuity_report.h" class MeasurementContainer { public: - MeasurementContainer(std::shared_ptr hdf5_meas, const std::string& meas_dir = "", bool use_receive_timestamp = true); + MeasurementContainer(std::shared_ptr hdf5_meas, const std::string& meas_dir = "", bool use_receive_timestamp = true); ~MeasurementContainer(); void CreatePublishers(); @@ -60,6 +61,7 @@ class MeasurementContainer double GetMinTimestampOfChannel(const std::string& channel_name) const; double GetMaxTimestampOfChannel(const std::string& channel_name) const; std::string GetChannelType(const std::string& channel_name) const; + std::string GetChannelEncoding(const std::string& channel_name) const; size_t GetChannelCumulativeEstimatedSize(const std::string& channel_name) const; std::map GetChannelMapping() const; @@ -92,8 +94,8 @@ class MeasurementContainer eCAL::CPublisher publisher_; long long message_counter_; - PublisherInfo(const std::string& topic_name, const std::string& topic_type = "", const std::string& topic_description = "") - : publisher_(topic_name, topic_type, topic_description) + PublisherInfo(const std::string& topic_name, const eCAL::SDataTypeInformation& info_) + : publisher_(topic_name, info_) , message_counter_(0) {} }; @@ -108,7 +110,7 @@ class MeasurementContainer PublisherInfo* publisher_info_; }; - std::shared_ptr hdf5_meas_; + std::shared_ptr hdf5_meas_; std::string meas_dir_; bool use_receive_timestamp_; diff --git a/app/play/play_core/src/play_thread.cpp b/app/play/play_core/src/play_thread.cpp index 3bf3a3f2c1..cb99277677 100644 --- a/app/play/play_core/src/play_thread.cpp +++ b/app/play/play_core/src/play_thread.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -273,7 +273,7 @@ void PlayThread::Run() if (!command.playing_) { EcalPlayLogger::Instance()->info("Playback finished"); - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_healthy, eCAL_Process_eSeverity_Level::proc_sev_level1, "Playback finished"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Playback finished"); } } } @@ -355,7 +355,7 @@ void PlayThread::SetPlaying_Private(bool playing) command_.sim_time_local_timestamp_ = now; EcalPlayLogger::Instance()->info("Playback pause"); - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_healthy, eCAL_Process_eSeverity_Level::proc_sev_level1, "Paused"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Paused"); } else if (!command_.playing_ && playing) { @@ -365,7 +365,7 @@ void PlayThread::SetPlaying_Private(bool playing) command_.sim_time_local_timestamp_ = std::chrono::steady_clock::now(); EcalPlayLogger::Instance()->info("Playback start"); - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_healthy, eCAL_Process_eSeverity_Level::proc_sev_level1, "Playing"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Playing"); } command_.playing_ = playing; @@ -576,7 +576,7 @@ void PlayThread::LogChannelMapping(const std::map& cha //// Measurement //// //////////////////////////////////////////////////////////////////////////////// -void PlayThread::SetMeasurement(const std::shared_ptr& measurement, const std::string& path) +void PlayThread::SetMeasurement(const std::shared_ptr& measurement, const std::string& path) { std::unique_ptr new_measurment_container; @@ -763,6 +763,19 @@ std::string PlayThread::GetChannelType(const std::string& channel_name) } } +std::string PlayThread::GetChannelEncoding(const std::string& channel_name) +{ + std::shared_lock measurement_lock(measurement_mutex_); + if (measurement_container_) + { + return measurement_container_->GetChannelEncoding(channel_name); + } + else + { + return std::string(""); + } +} + void PlayThread::CalculateEstimatedSizeForChannels() { std::shared_lock measurement_lock(measurement_mutex_); diff --git a/app/play/play_core/src/play_thread.h b/app/play/play_core/src/play_thread.h index 5e782f3b0e..23c2d34342 100644 --- a/app/play/play_core/src/play_thread.h +++ b/app/play/play_core/src/play_thread.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,7 +79,7 @@ class PlayThread : public InterruptibleThread * @param measurement The new measurement * @param path The (optional) path from where the measurement was loaded */ - void SetMeasurement(const std::shared_ptr& measurement, const std::string& path = ""); + void SetMeasurement(const std::shared_ptr& measurement, const std::string& path = ""); /** * @brief Returns whether a measurement has successfully been loaded @@ -157,6 +157,15 @@ class PlayThread : public InterruptibleThread **/ std::string GetChannelType(const std::string& channel_name); + /** + * @brief Gets the data type of the given channel + * + * @param channel_name channel name + * + * @return channel type + **/ + std::string GetChannelEncoding(const std::string& channel_name); + void CalculateEstimatedSizeForChannels(); /** diff --git a/app/play/play_gui/CMakeLists.txt b/app/play/play_gui/CMakeLists.txt index 3dff50e5e9..8378a32971 100644 --- a/app/play/play_gui/CMakeLists.txt +++ b/app/play/play_gui/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -139,7 +139,7 @@ ecal_add_app_qt(${PROJECT_NAME} ) create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE tclap::tclap CustomTclap eCAL::play_core @@ -160,7 +160,7 @@ if (WIN32 AND (${QT_VERSION_MAJOR} EQUAL 5)) # Maybe we can re-enable the functionality with the following external lib: # https://github.com/oblivioncth/Qx # - target_link_libraries (${PROJECT_NAME} + target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::WinExtras ) endif() diff --git a/app/play/play_gui/src/main.cpp b/app/play/play_gui/src/main.cpp index 906771dd7a..48c6afb939 100644 --- a/app/play/play_gui/src/main.cpp +++ b/app/play/play_gui/src/main.cpp @@ -159,7 +159,7 @@ int main(int argc, char *argv[]) ////////////////////////////////////////////////////////////////////////////// // Just make sure that eCAL is initialized - eCAL::Initialize(0, nullptr, "eCALPlayGUI", eCAL::Init::Default | eCAL::Init::ProcessReg | eCAL::Init::Publisher | eCAL::Init::Service | eCAL::Init::Monitoring); + eCAL::Initialize("eCALPlayGUI", eCAL::Init::Default | eCAL::Init::Publisher | eCAL::Init::Service | eCAL::Init::Monitoring); // For linux big measurements require more file descriptors than the default value #ifdef ECAL_OS_LINUX diff --git a/app/play/play_gui/src/q_ecal_play.cpp b/app/play/play_gui/src/q_ecal_play.cpp index b9c87383a5..7cf7084a94 100644 --- a/app/play/play_gui/src/q_ecal_play.cpp +++ b/app/play/play_gui/src/q_ecal_play.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -128,6 +128,11 @@ std::string QEcalPlay::channelType(const std::string& channel_name) const return ecal_play_.GetChannelType(channel_name); } +std::string QEcalPlay::channelEncoding(const std::string& channel_name) const +{ + return ecal_play_.GetChannelEncoding(channel_name); +} + size_t QEcalPlay::channelCumulativeEstimatedSize(const std::string& channel_name) const { return ecal_play_.GetChannelCumulativeEstimatedSize(channel_name); diff --git a/app/play/play_gui/src/q_ecal_play.h b/app/play/play_gui/src/q_ecal_play.h index a47210984e..c078ff7913 100644 --- a/app/play/play_gui/src/q_ecal_play.h +++ b/app/play/play_gui/src/q_ecal_play.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -59,6 +59,7 @@ class QEcalPlay : public QObject double minTimestampOfChannel(const std::string& channel_name) const; double maxTimestampOfChannel(const std::string& channel_name) const; std::string channelType(const std::string& channel_name) const; + std::string channelEncoding(const std::string& channel_name) const; size_t channelCumulativeEstimatedSize(const std::string& channel_name) const; std::map createContinuityReport() const; std::map messageCounters() const; diff --git a/app/play/play_gui/src/widgets/about_dialog/about_dialog.cpp b/app/play/play_gui/src/widgets/about_dialog/about_dialog.cpp index 1af4b11de5..13909f2953 100644 --- a/app/play/play_gui/src/widgets/about_dialog/about_dialog.cpp +++ b/app/play/play_gui/src/widgets/about_dialog/about_dialog.cpp @@ -20,9 +20,10 @@ #include "about_dialog.h" #include "ecal_play_globals.h" -#include +#include #include +#include AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) @@ -30,6 +31,12 @@ AboutDialog::AboutDialog(QWidget *parent) ui_.setupUi(this); ui_.version_label->setText("Version: " + QString(EcalPlayGlobals::VERSION_STRING)); ui_.ecalversion_label->setText("eCAL " + QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + + ui_.ecal_runtime_version_string_label->setText(QString::fromStdString(eCAL::GetVersionString()) + " (" + QString::fromStdString(eCAL::GetVersionDateString()) + ")"); + ui_.ecal_compiletime_versin_string_label->setText(QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + ui_.qt_runtime_version_string_label->setText(QString(qVersion())); + ui_.qt_compiletime_version_string_label->setText(QString(QT_VERSION_STR)); + connect(ui_.button_box->button(QDialogButtonBox::StandardButton::Ok), SIGNAL(clicked()), this, SLOT(close())); } diff --git a/app/play/play_gui/src/widgets/about_dialog/about_dialog.ui b/app/play/play_gui/src/widgets/about_dialog/about_dialog.ui index 22aff775ca..13105c55c4 100644 --- a/app/play/play_gui/src/widgets/about_dialog/about_dialog.ui +++ b/app/play/play_gui/src/widgets/about_dialog/about_dialog.ui @@ -62,7 +62,6 @@ Advanced Engineering Department Developed by Florian Reimold Based on work by Claudiu Vasilescu, Andreea Popa - @@ -73,6 +72,68 @@ Based on work by Claudiu Vasilescu, Andreea Popa + + + + + + + Qt runtime version: + + + + + + + qt-runtime-version + + + + + + + eCAL runtime version: + + + + + + + ecal-runtime-version + + + + + + + eCAL compile-time version: + + + + + + + ecal-compiletime-version + + + + + + + Qt compile-time version: + + + + + + + qt-compiletime-version + + + + + + diff --git a/app/play/play_gui/src/widgets/channel_widget/channel_widget.cpp b/app/play/play_gui/src/widgets/channel_widget/channel_widget.cpp index c7564a8262..33ea84048b 100644 --- a/app/play/play_gui/src/widgets/channel_widget/channel_widget.cpp +++ b/app/play/play_gui/src/widgets/channel_widget/channel_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -600,7 +600,7 @@ void ChannelWidget::setInitButtonToDeInit() void ChannelWidget::autoSizeColumns() { - ChannelTreeItem* dummy_item = new ChannelTreeItem("CameraSensorMapFusionCAF___", "Dummy_type", 99999999, 99999999.0, 99999999.0, 99999999, 99999999, 99999999); + ChannelTreeItem* dummy_item = new ChannelTreeItem("CameraSensorMapFusionCAF___", "proto", "Dummy_type", 99999999, 99999999.0, 99999999.0, 99999999, 99999999, 99999999); channel_model_->insertItem(dummy_item); for (int i = 0; i < channel_model_->columnCount(); i++) diff --git a/app/play/play_gui/src/widgets/models/channel_tree_item.cpp b/app/play/play_gui/src/widgets/models/channel_tree_item.cpp index 04bc8aa871..9dd3acfed0 100644 --- a/app/play/play_gui/src/widgets/models/channel_tree_item.cpp +++ b/app/play/play_gui/src/widgets/models/channel_tree_item.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,12 +40,13 @@ ChannelTreeItem::ChannelTreeItem(const QString& source_name) , duration_(0) {} -ChannelTreeItem::ChannelTreeItem(const QString& source_name, const QString& channel_type, size_t total_channel_size, +ChannelTreeItem::ChannelTreeItem(const QString& source_name, const QString& channel_encoding, const QString& channel_type, size_t total_channel_size, double min_channel_timestamp, double max_channel_timestamp, long long expected_frames, long long existing_frames, double duration) : QAbstractTreeItem() , enabled_(true) , source_name_(source_name) , target_name_(source_name) + , channel_encoding_(channel_encoding) , channel_type_(channel_type) , total_channel_size_(total_channel_size) , min_channel_timestamp_(min_channel_timestamp) @@ -76,6 +77,8 @@ QVariant ChannelTreeItem::data(Columns column, Qt::ItemDataRole role) const return source_name_; case ChannelTreeItem::Columns::TARGET_CHANNEL_NAME: return target_name_; + case ChannelTreeItem::Columns::CHANNEL_ENCODING: + return channel_encoding_; case ChannelTreeItem::Columns::CHANNEL_TYPE: return channel_type_; case ChannelTreeItem::Columns::TOTAL_CHANNEL_SIZE: diff --git a/app/play/play_gui/src/widgets/models/channel_tree_item.h b/app/play/play_gui/src/widgets/models/channel_tree_item.h index eb143bf37f..95d987444f 100644 --- a/app/play/play_gui/src/widgets/models/channel_tree_item.h +++ b/app/play/play_gui/src/widgets/models/channel_tree_item.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ class ChannelTreeItem : public QAbstractTreeItem SOURCE_CHANNEL_NAME, TARGET_CHANNEL_NAME, + CHANNEL_ENCODING, CHANNEL_TYPE, TOTAL_CHANNEL_SIZE, @@ -47,7 +48,7 @@ class ChannelTreeItem : public QAbstractTreeItem }; ChannelTreeItem(const QString& source_name); - ChannelTreeItem(const QString& source_name, const QString& channel_type, size_t total_channel_size, + ChannelTreeItem(const QString& source_name, const QString& channel_encoding, const QString& channel_type, size_t total_channel_size, double min_channel_timestamp, double max_channel_timestamp, long long expected_frames, long long existing_frames, double duration); ~ChannelTreeItem(); @@ -76,6 +77,7 @@ class ChannelTreeItem : public QAbstractTreeItem QString source_name_; QString target_name_; + QString channel_encoding_; QString channel_type_; size_t total_channel_size_; diff --git a/app/play/play_gui/src/widgets/models/channel_tree_model.cpp b/app/play/play_gui/src/widgets/models/channel_tree_model.cpp index 0be7a1cee7..42f8c1fc88 100644 --- a/app/play/play_gui/src/widgets/models/channel_tree_model.cpp +++ b/app/play/play_gui/src/widgets/models/channel_tree_model.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -237,9 +237,10 @@ void ChannelTreeModel::reload() double minTimestamp = QEcalPlay::instance()->minTimestampOfChannel(name); double maxTimestamp = QEcalPlay::instance()->maxTimestampOfChannel(name); std::string channel_type = QEcalPlay::instance()->channelType(name); + std::string channel_encoding = QEcalPlay::instance()->channelEncoding(name); size_t total_channel_size = QEcalPlay::instance()->channelCumulativeEstimatedSize(name); - ChannelTreeItem* channel_item = new ChannelTreeItem(name.c_str(), channel_type.c_str(), total_channel_size, + ChannelTreeItem* channel_item = new ChannelTreeItem(name.c_str(), channel_encoding.c_str(), channel_type.c_str(), total_channel_size, minTimestamp, maxTimestamp, expected_frames, existing_frames, duration); new_channel_list.push_back(channel_item); } diff --git a/app/play/play_gui/src/widgets/models/channel_tree_model.h b/app/play/play_gui/src/widgets/models/channel_tree_model.h index 12a62c5df4..abb06b6277 100644 --- a/app/play/play_gui/src/widgets/models/channel_tree_model.h +++ b/app/play/play_gui/src/widgets/models/channel_tree_model.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ class ChannelTreeModel : public QAbstractTreeModel { ENABLED, CHANNEL_NAME, + CHANNEL_ENCODING, CHANNEL_TYPE, TOTAL_CHANNEL_SIZE, @@ -82,6 +83,7 @@ class ChannelTreeModel : public QAbstractTreeModel { { Columns::ENABLED, ""} , { Columns::CHANNEL_NAME, "Channel" } , + { Columns::CHANNEL_ENCODING, "Channel encoding"}, { Columns::CHANNEL_TYPE, "Channel type"}, { Columns::MESSAGE_COUNTER, "Published messages" } , { Columns::TOTAL_CHANNEL_SIZE, "Total estimated channel size" } , @@ -98,6 +100,7 @@ class ChannelTreeModel : public QAbstractTreeModel { { Columns::ENABLED, (int)ChannelTreeItem::Columns::ENABLED }, { Columns::CHANNEL_NAME, (int)ChannelTreeItem::Columns::SOURCE_CHANNEL_NAME }, + { Columns::CHANNEL_ENCODING, (int)ChannelTreeItem::Columns::CHANNEL_ENCODING}, { Columns::CHANNEL_TYPE, (int)ChannelTreeItem::Columns::CHANNEL_TYPE}, { Columns::TOTAL_CHANNEL_SIZE, (int)ChannelTreeItem::Columns::TOTAL_CHANNEL_SIZE}, { Columns::MESSAGE_COUNTER, -1 }, diff --git a/app/play/play_gui/src/widgets/scenario_widget/scenario_model.h b/app/play/play_gui/src/widgets/scenario_widget/scenario_model.h index 4c0290f32c..313d4f624a 100644 --- a/app/play/play_gui/src/widgets/scenario_widget/scenario_model.h +++ b/app/play/play_gui/src/widgets/scenario_widget/scenario_model.h @@ -21,7 +21,7 @@ #include -#include +#include #include diff --git a/app/rec/rec_client_cli/src/ecal_rec_cli.cpp b/app/rec/rec_client_cli/src/ecal_rec_cli.cpp index 1fb19770f3..7cf453aaee 100644 --- a/app/rec/rec_client_cli/src/ecal_rec_cli.cpp +++ b/app/rec/rec_client_cli/src/ecal_rec_cli.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -427,7 +427,7 @@ void UpdateEcalState() if (!rec_status.initialized_) { - eCAL::Process::SetState(eCAL_Process_eSeverity::proc_sev_warning, eCAL_Process_eSeverity_Level::proc_sev_level1 + eCAL::Process::SetState(eCAL::Process::eSeverity::warning, eCAL::Process::eSeverityLevel::level1 , "Not initialized"); } else @@ -467,13 +467,13 @@ void UpdateEcalState() } } - eCAL_Process_eSeverity severity(eCAL_Process_eSeverity::proc_sev_healthy); + eCAL::Process::eSeverity severity(eCAL::Process::eSeverity::healthy); std::string state_string; // General error if (!rec_status.info_.first) { - severity = eCAL_Process_eSeverity::proc_sev_critical; + severity = eCAL::Process::eSeverity::critical; state_string = "[" + rec_status.info_.second + "] "; } @@ -488,7 +488,7 @@ void UpdateEcalState() } if (rec_status.subscribed_topics_.empty()) - severity = std::max(severity, eCAL_Process_eSeverity::proc_sev_warning); + severity = std::max(severity, eCAL::Process::eSeverity::warning); state_string += "(" + std::to_string(rec_status.subscribed_topics_.size()) + " Topics) "; @@ -504,7 +504,7 @@ void UpdateEcalState() state_string += ", " + std::to_string(flushing_jobs_.size()) + " job" + (flushing_jobs_.size() > 1 ? "s" : "") + " uploading"; } - eCAL::Process::SetState(severity, eCAL_Process_eSeverity_Level::proc_sev_level1, state_string.c_str()); + eCAL::Process::SetState(severity, eCAL::Process::eSeverityLevel::level1, state_string.c_str()); } } diff --git a/app/rec/rec_client_core/CMakeLists.txt b/app/rec/rec_client_core/CMakeLists.txt index ec7312dd5e..663fc040df 100644 --- a/app/rec/rec_client_core/CMakeLists.txt +++ b/app/rec/rec_client_core/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -94,11 +94,11 @@ target_link_libraries(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PUBLIC protobuf::libprotobuf - eCAL::core + eCAL::protobuf_core eCAL::core_pb eCAL::app_pb PRIVATE - eCAL::measurement_hdf5 + eCAL::hdf5 ThreadingUtils Threads::Threads eCAL::ecal-utils diff --git a/app/rec/rec_client_core/include/rec_client_core/ecal_rec_logger.h b/app/rec/rec_client_core/include/rec_client_core/ecal_rec_logger.h index 1945992063..d8155e6487 100644 --- a/app/rec/rec_client_core/include/rec_client_core/ecal_rec_logger.h +++ b/app/rec/rec_client_core/include/rec_client_core/ecal_rec_logger.h @@ -52,7 +52,7 @@ namespace eCAL static const int MAXIMUM_ROTATING_FILES = 5; static const int FIVE_MEGABYTES = 5 * 1024 * 1024; - auto ecal_data_path = eCAL::Util::GeteCALLogPath(); + auto ecal_data_path = eCAL::Util::GeteCALLogDir(); std::string log_filename = ecal_data_path + ECAL_REC_NAME + ".log"; // create console logger and rotating file logger with maximum size 5MB and maximum 5 rotating files diff --git a/app/rec/rec_client_core/include/rec_client_core/state.h b/app/rec/rec_client_core/include/rec_client_core/state.h index 23e16e084f..2e60cb962f 100644 --- a/app/rec/rec_client_core/include/rec_client_core/state.h +++ b/app/rec/rec_client_core/include/rec_client_core/state.h @@ -26,7 +26,7 @@ #include #include -#include +#include namespace eCAL { diff --git a/app/rec/rec_client_core/include/rec_client_core/topic_info.h b/app/rec/rec_client_core/include/rec_client_core/topic_info.h index aa7b7d3b6f..19e5f4986b 100644 --- a/app/rec/rec_client_core/include/rec_client_core/topic_info.h +++ b/app/rec/rec_client_core/include/rec_client_core/topic_info.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace eCAL { @@ -29,17 +30,48 @@ namespace eCAL { struct TopicInfo { - TopicInfo(const std::string& type, const std::string& description) - : type_(type), description_(description), description_quality_(0) + TopicInfo(const eCAL::SDataTypeInformation& tinfo) + : tinfo_(tinfo) {} + + TopicInfo(const std::string& type, const std::string& encoding, const std::string& description) + : tinfo_{ type, encoding, description } + {} + TopicInfo() - : description_quality_(0) {} - std::string type_; - std::string description_; + eCAL::SDataTypeInformation tinfo_; + + // This should be removed once internally SDatatypeInformation is saved alongside with the publisher ID.. + std::string GetLegacyType() const + { + if (tinfo_.encoding.empty()) + { + return tinfo_.name; + } + else + { + return tinfo_.encoding + ":" + tinfo_.name; + } + } + + void SetLegacyType(const std::string& combined_topic_type_) + { + auto pos = combined_topic_type_.find(':'); + if (pos == std::string::npos) + { + tinfo_.encoding = ""; + tinfo_.name = combined_topic_type_; + } + else + { + tinfo_.encoding = combined_topic_type_.substr(0, pos); + tinfo_.name = combined_topic_type_.substr(pos + 1); + } + } - int description_quality_; + int description_quality_ = 0; std::map> publishers_; }; diff --git a/app/rec/rec_client_core/src/addons/addon_manager.cpp b/app/rec/rec_client_core/src/addons/addon_manager.cpp index fa131092a6..14683afe70 100644 --- a/app/rec/rec_client_core/src/addons/addon_manager.cpp +++ b/app/rec/rec_client_core/src/addons/addon_manager.cpp @@ -26,7 +26,7 @@ #include -#include +#include namespace eCAL { diff --git a/app/rec/rec_client_core/src/ecal_rec.cpp b/app/rec/rec_client_core/src/ecal_rec.cpp index 87d83d1ea7..e9e9e75f07 100644 --- a/app/rec/rec_client_core/src/ecal_rec.cpp +++ b/app/rec/rec_client_core/src/ecal_rec.cpp @@ -36,8 +36,7 @@ namespace eCAL EcalRec::EcalRec() { - eCAL::Initialize(0, nullptr, "eCALRecClient", eCAL::Init::Default | eCAL::Init::Monitoring); - eCAL::Monitoring::SetFilterState(false); + eCAL::Initialize("eCALRecClient", eCAL::Init::Default | eCAL::Init::Monitoring); recorder_ = std::make_unique(); } diff --git a/app/rec/rec_client_core/src/ecal_rec_impl.cpp b/app/rec/rec_client_core/src/ecal_rec_impl.cpp index 069befae17..444b79160b 100644 --- a/app/rec/rec_client_core/src/ecal_rec_impl.cpp +++ b/app/rec/rec_client_core/src/ecal_rec_impl.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -695,12 +695,12 @@ namespace eCAL return subscribed_topics; } - void EcalRecImpl::EcalMessageReceived(const char* topic_name, const eCAL::SReceiveCallbackData* callback_data) + void EcalRecImpl::EcalMessageReceived(const eCAL::STopicId& topic_id_, const eCAL::SReceiveCallbackData& data_) { auto ecal_receive_time = eCAL::Time::ecal_clock::now(); auto system_receive_time = std::chrono::steady_clock::now(); - std::shared_ptr frame = std::make_shared(callback_data, topic_name, ecal_receive_time, system_receive_time); + std::shared_ptr frame = std::make_shared(&data_, topic_id_.topic_name, ecal_receive_time, system_receive_time); pre_buffer_.push_back(frame); @@ -821,14 +821,14 @@ namespace eCAL if (subscriber_map_.find(topic) == subscriber_map_.end()) { EcalRecLogger::Instance()->info("Subscribing to " + topic); - std::unique_ptr subscriber = std::make_unique(); - if (!subscriber->Create(topic)) + std::unique_ptr subscriber = std::make_unique(topic); + if (!subscriber) { EcalRecLogger::Instance()->error("Error creating subscriber for topic " + topic); info_ = { false, "Error creating eCAL subsribers" }; continue; } - if (!subscriber->AddReceiveCallback(std::bind(&EcalRecImpl::EcalMessageReceived, this, std::placeholders::_1, std::placeholders::_2))) + if (!subscriber->SetReceiveCallback(std::bind(&EcalRecImpl::EcalMessageReceived, this, std::placeholders::_1, std::placeholders::_3))) { EcalRecLogger::Instance()->error("Error adding callback for subscriber on topic " + topic); info_ = { false, "Error creating eCAL subsribers" }; @@ -848,7 +848,6 @@ namespace eCAL { EcalRecLogger::Instance()->info("Unsubscribing from " + subscriber_it->first); - subscriber_it->second->Destroy(); subscriber_it = subscriber_map_.erase(subscriber_it); } else diff --git a/app/rec/rec_client_core/src/ecal_rec_impl.h b/app/rec/rec_client_core/src/ecal_rec_impl.h index 5e37d4eafa..38603969a3 100644 --- a/app/rec/rec_client_core/src/ecal_rec_impl.h +++ b/app/rec/rec_client_core/src/ecal_rec_impl.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,8 +40,7 @@ #include "frame_buffer.h" -#include -#include +#include namespace eCAL { @@ -115,7 +114,7 @@ namespace eCAL std::set GetSubscribedTopics() const; - void EcalMessageReceived(const char* topic_name, const eCAL::SReceiveCallbackData* callback_data); + void EcalMessageReceived(const eCAL::STopicId& topic_id_, const eCAL::SReceiveCallbackData& data_); ////////////////////////////////////// //// API for external threads //// diff --git a/app/rec/rec_client_core/src/frame.h b/app/rec/rec_client_core/src/frame.h index d65d1f2326..28dac992d7 100644 --- a/app/rec/rec_client_core/src/frame.h +++ b/app/rec/rec_client_core/src/frame.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,8 +22,8 @@ #include #include #include -#include -#include +#include +#include namespace eCAL { diff --git a/app/rec/rec_client_core/src/job/hdf5_writer_thread.cpp b/app/rec/rec_client_core/src/job/hdf5_writer_thread.cpp index c3ddd4902f..10065714cb 100644 --- a/app/rec/rec_client_core/src/job/hdf5_writer_thread.cpp +++ b/app/rec/rec_client_core/src/job/hdf5_writer_thread.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,6 @@ */ #include "hdf5_writer_thread.h" -#include #include "rec_client_core/ecal_rec_logger.h" @@ -42,7 +41,7 @@ namespace eCAL , new_topic_info_map_available_(true) , flushing_ (false) { - hdf5_writer_ = std::make_unique(); + hdf5_writer_ = std::make_unique(); } Hdf5WriterThread::~Hdf5WriterThread() @@ -169,8 +168,8 @@ namespace eCAL for (const auto& topic : topic_info_map_to_set) { - hdf5_writer_->SetChannelType(topic.first, topic.second.type_); - hdf5_writer_->SetChannelDescription(topic.first, topic.second.description_); + eCAL::experimental::measurement::base::DataTypeInformation const topic_info{ topic.second.tinfo_.name, topic.second.tinfo_.encoding, topic.second.tinfo_.descriptor }; + hdf5_writer_->SetChannelDataTypeInformation(topic.first, topic_info); } } else if (frame) @@ -186,7 +185,7 @@ namespace eCAL frame->data_.size(), std::chrono::duration_cast(frame->ecal_publish_time_.time_since_epoch()).count(), std::chrono::duration_cast(frame->ecal_receive_time_.time_since_epoch()).count(), - frame->topic_name_, + frame->topic_name_, frame->id_, frame->clock_ )) @@ -265,7 +264,7 @@ namespace eCAL #endif // NDEBUG std::unique_lock hdf5_writer_lock(hdf5_writer_mutex_); - if (hdf5_writer_->Open(hdf5_dir)) + if (hdf5_writer_->Open(hdf5_dir, eCAL::eh5::v2::eAccessType::CREATE)) { #ifndef NDEBUG EcalRecLogger::Instance()->debug("Hdf5WriterThread::Open(): Successfully opened HDF5-Writer with path \"" + hdf5_dir + "\""); diff --git a/app/rec/rec_client_core/src/job/hdf5_writer_thread.h b/app/rec/rec_client_core/src/job/hdf5_writer_thread.h index 042b64eeba..91e3982c42 100644 --- a/app/rec/rec_client_core/src/job/hdf5_writer_thread.h +++ b/app/rec/rec_client_core/src/job/hdf5_writer_thread.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ #pragma once #include -#include +#include #include #include @@ -94,7 +94,7 @@ namespace eCAL mutable RecHdf5JobStatus last_status_; mutable std::mutex hdf5_writer_mutex_; - std::unique_ptr hdf5_writer_; + std::unique_ptr hdf5_writer_; std::atomic flushing_; diff --git a/app/rec/rec_client_core/src/job/record_job.cpp b/app/rec/rec_client_core/src/job/record_job.cpp index b0715a568a..4016c70f08 100644 --- a/app/rec/rec_client_core/src/job/record_job.cpp +++ b/app/rec/rec_client_core/src/job/record_job.cpp @@ -164,7 +164,7 @@ namespace eCAL } } - // Copy ecal.ini + // Copy ecal.yaml #ifdef CopyFile #define CopyFile_6376c040f4f54106b205ef6ddbb2090a CopyFile #undef CopyFile @@ -174,28 +174,28 @@ namespace eCAL if (ecal_ini_original_path.empty()) { - const std::string error_message = "Error copying ecal.ini: The system information does not contain \"Default INI\" identifier."; + const std::string error_message = "Error copying ecal.yaml: The system information does not contain \"Default INI\" identifier."; info_ = { false, error_message }; EcalRecLogger::Instance()->error(error_message); } if (EcalUtils::Filesystem::IsFile(ecal_ini_original_path)) { - std::string ecal_ini_dest_path = EcalUtils::Filesystem::ToNativeSeperators(hostname_dir + "/ecal.ini"); - EcalRecLogger::Instance()->info("Copying ecal.ini from \"" + ecal_ini_original_path + "\" to \"" + ecal_ini_dest_path + "\""); + std::string ecal_ini_dest_path = EcalUtils::Filesystem::ToNativeSeperators(hostname_dir + "/ecal.yaml"); + EcalRecLogger::Instance()->info("Copying ecal.yaml from \"" + ecal_ini_original_path + "\" to \"" + ecal_ini_dest_path + "\""); if (!EcalUtils::Filesystem::CopyFile(ecal_ini_original_path, ecal_ini_dest_path, EcalUtils::Filesystem::OsStyle::Current)) { - const std::string error_message = "Error copying ecal.ini file to \"" + ecal_ini_dest_path + "\""; + const std::string error_message = "Error copying ecal.yaml file to \"" + ecal_ini_dest_path + "\""; info_ = { false, error_message }; EcalRecLogger::Instance()->error(error_message); } } else { - const std::string error_message = "Warning: ecal.ini does not exist and will not be copied."; + const std::string error_message = "Warning: ecal.yaml does not exist and will not be copied."; info_ = { false, error_message }; - EcalRecLogger::Instance()->warn("Warning: ecal.ini does not exist and will not be copied."); + EcalRecLogger::Instance()->warn("Warning: ecal.yaml does not exist and will not be copied."); } } #ifdef CopyFile_6376c040f4f54106b205ef6ddbb2090a diff --git a/app/rec/rec_client_core/src/monitoring_thread.cpp b/app/rec/rec_client_core/src/monitoring_thread.cpp index af1fae8b06..fc39479a4a 100644 --- a/app/rec/rec_client_core/src/monitoring_thread.cpp +++ b/app/rec/rec_client_core/src/monitoring_thread.cpp @@ -84,14 +84,17 @@ namespace eCAL if (topic_info_map_it == topic_info_map_.end()) { // Create a new topic entry - topic_info_map_.emplace(topic.tname(), eCAL::rec::TopicInfo("", "")); + topic_info_map_.emplace(topic.tname(), eCAL::rec::TopicInfo("", "", "")); topic_info_map_it = topic_info_map_.find(topic.tname()); } + // Create combined encoding:type type (to be fully compatible to old behavior) + std::string combined_enc_type = eCAL::Util::CombinedTopicEncodingAndType(topic.tdatatype().encoding(), topic.tdatatype().name()); + // Evaluate the quality of the current descriptor information int this_topic_info_quality = 0; - if (!topic.tdesc().empty()) + if (!topic.tdatatype().desc().empty()) { this_topic_info_quality |= DESCRIPTION_AVAILABLE_QUALITYBIT; } @@ -114,7 +117,7 @@ namespace eCAL } } - if (!topic.ttype().empty()) + if (!combined_enc_type.empty()) { this_topic_info_quality |= TYPE_AVAILABLE_QUALITYBIT; } @@ -125,35 +128,35 @@ namespace eCAL if (channel_descriptor_map_it == channel_descriptor_map.end()) { // Save the new descriptor - channel_descriptor_map.emplace(topic.tname(), std::make_pair(this_topic_info_quality, std::make_pair(topic.ttype(), topic.tdesc()))); + channel_descriptor_map.emplace(topic.tname(), std::make_pair(this_topic_info_quality, std::make_pair(combined_enc_type, topic.tdatatype().desc()))); } else { if(channel_descriptor_map_it->second.first < this_topic_info_quality) { // If the old descriptor has a lower quality than the current descriptor, we may overwrite it! - channel_descriptor_map_it->second = std::make_pair(this_topic_info_quality, std::make_pair(topic.ttype(), topic.tdesc())); + channel_descriptor_map_it->second = std::make_pair(this_topic_info_quality, std::make_pair(combined_enc_type, topic.tdatatype().desc())); } } } // Update the type_descriptor_map (can of course only work if we have the type information available) - if (!topic.ttype().empty()) + if (!combined_enc_type.empty()) { int quality_for_other_channels = (this_topic_info_quality & ~INFO_COMES_FROM_CORRECT_TOPIC_QUALITYBIT); - auto type_descriptor_map_it = type_descriptor_map.find(topic.ttype()); + auto type_descriptor_map_it = type_descriptor_map.find(combined_enc_type); if (type_descriptor_map_it == type_descriptor_map.end()) { // Save the new descriptor - type_descriptor_map.emplace(topic.ttype(), std::make_pair(quality_for_other_channels, topic.tdesc())); + type_descriptor_map.emplace(combined_enc_type, std::make_pair(quality_for_other_channels, topic.tdatatype().desc())); } else { if(type_descriptor_map_it->second.first < quality_for_other_channels) { // If the old descriptor has a lower quality than the current descriptor, we may overwrite it! - type_descriptor_map_it->second = std::make_pair(quality_for_other_channels, topic.tdesc()); + type_descriptor_map_it->second = std::make_pair(quality_for_other_channels, topic.tdatatype().desc()); } } } @@ -166,18 +169,18 @@ namespace eCAL if ((channel_descriptor_entry_it != channel_descriptor_map.end()) && (channel_descriptor_entry_it->second.first >= topic_info_map_entry.second.description_quality_)) { - topic_info_map_entry.second.type_ = channel_descriptor_entry_it->second.second.first; - topic_info_map_entry.second.description_ = channel_descriptor_entry_it->second.second.second; + topic_info_map_entry.second.SetLegacyType(channel_descriptor_entry_it->second.second.first); + topic_info_map_entry.second.tinfo_.descriptor = channel_descriptor_entry_it->second.second.second; topic_info_map_entry.second.description_quality_ = channel_descriptor_entry_it->second.first; } - if (!topic_info_map_entry.second.type_.empty()) + if (!topic_info_map_entry.second.GetLegacyType().empty()) { - auto type_descriptor_entry_it = type_descriptor_map.find(topic_info_map_entry.second.type_); + auto type_descriptor_entry_it = type_descriptor_map.find(topic_info_map_entry.second.GetLegacyType()); if ((type_descriptor_entry_it != type_descriptor_map.end()) && (type_descriptor_entry_it->second.first >= topic_info_map_entry.second.description_quality_)) { - topic_info_map_entry.second.description_ = type_descriptor_entry_it->second.second; + topic_info_map_entry.second.tinfo_.descriptor = type_descriptor_entry_it->second.second; topic_info_map_entry.second.description_quality_ = type_descriptor_entry_it->second.first; } } diff --git a/app/rec/rec_gui/CMakeLists.txt b/app/rec/rec_gui/CMakeLists.txt index 537a235e80..d01b582c42 100644 --- a/app/rec/rec_gui/CMakeLists.txt +++ b/app/rec/rec_gui/CMakeLists.txt @@ -170,7 +170,7 @@ ecal_add_app_qt(${PROJECT_NAME} ) create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE tclap::tclap protobuf::libprotobuf eCAL::core @@ -195,7 +195,7 @@ if (WIN32 AND (${QT_VERSION_MAJOR} EQUAL 5)) # Maybe we can re-enable the functionality with the following external lib: # https://github.com/oblivioncth/Qx # - target_link_libraries (${PROJECT_NAME} + target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::WinExtras ) endif() diff --git a/app/rec/rec_gui/src/main.cpp b/app/rec/rec_gui/src/main.cpp index 4f4e8ff9b7..c17cacc707 100644 --- a/app/rec/rec_gui/src/main.cpp +++ b/app/rec/rec_gui/src/main.cpp @@ -136,8 +136,7 @@ int main(int argc, char *argv[]) } // Just make sure that eCAL is initialized - eCAL::Initialize(0, nullptr, "eCALRecGUI", eCAL::Init::Default | eCAL::Init::Service | eCAL::Init::Monitoring); - eCAL::Monitoring::SetFilterState(false); + eCAL::Initialize("eCALRecGUI", eCAL::Init::Default | eCAL::Init::Service | eCAL::Init::Monitoring); EcalRecGui* w = new EcalRecGui(); w->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose); diff --git a/app/rec/rec_gui/src/qecalrec.cpp b/app/rec/rec_gui/src/qecalrec.cpp index 1e77e17e7d..70885a6b68 100644 --- a/app/rec/rec_gui/src/qecalrec.cpp +++ b/app/rec/rec_gui/src/qecalrec.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include @@ -78,7 +78,7 @@ Date: $HOST{TIME %F %R} auto status = this->status(); auto config = this->enabledRecClients(); auto ecalstate = eCAL::rec_server::GetProcessSeverity(status, config); - eCAL::Process::SetState(ecalstate.first, eCAL_Process_eSeverity_Level::proc_sev_level1, ecalstate.second.c_str()); + eCAL::Process::SetState(ecalstate.first, eCAL::Process::eSeverityLevel::level1, ecalstate.second.c_str()); }); ecal_state_update_timer_->start(ecal_state_update_time_ms_); diff --git a/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.cpp b/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.cpp index 8b7719d5e8..3126a1193a 100644 --- a/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.cpp +++ b/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.cpp @@ -20,9 +20,10 @@ #include "about_dialog.h" #include "rec_client_core/ecal_rec_defs.h" -#include +#include #include +#include AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) @@ -30,6 +31,12 @@ AboutDialog::AboutDialog(QWidget *parent) ui_.setupUi(this); ui_.version_label->setText("Version: " + QString(ECAL_REC_VERSION_STRING)); ui_.ecalversion_label->setText("eCAL " + QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + + ui_.ecal_runtime_version_string_label->setText(QString::fromStdString(eCAL::GetVersionString()) + " (" + QString::fromStdString(eCAL::GetVersionDateString()) + ")"); + ui_.ecal_compiletime_versin_string_label->setText(QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + ui_.qt_runtime_version_string_label->setText(QString(qVersion())); + ui_.qt_compiletime_version_string_label->setText(QString(QT_VERSION_STR)); + connect(ui_.button_box->button(QDialogButtonBox::StandardButton::Ok), SIGNAL(clicked()), this, SLOT(close())); } diff --git a/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.ui b/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.ui index eff394f7fa..7b63b3f74a 100644 --- a/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.ui +++ b/app/rec/rec_gui/src/widgets/about_dialog/about_dialog.ui @@ -60,7 +60,8 @@ © 2019 Continental AG Advanced Engineering Department -Developed by Florian Reimold +Developed by Florian Reimold + Qt::PlainText @@ -70,6 +71,68 @@ Developed by Florian Reimold + + + + + + + Qt runtime version: + + + + + + + qt-runtime-version + + + + + + + eCAL runtime version: + + + + + + + ecal-runtime-version + + + + + + + eCAL compile-time version: + + + + + + + ecal-compiletime-version + + + + + + + Qt compile-time version: + + + + + + + qt-compiletime-version + + + + + + diff --git a/app/rec/rec_gui/src/widgets/recording_history_widget/job_history_model.cpp b/app/rec/rec_gui/src/widgets/recording_history_widget/job_history_model.cpp index 006c496bed..d9afe991d5 100644 --- a/app/rec/rec_gui/src/widgets/recording_history_widget/job_history_model.cpp +++ b/app/rec/rec_gui/src/widgets/recording_history_widget/job_history_model.cpp @@ -158,15 +158,15 @@ void JobHistoryModel::setRecorderStatuses(const eCAL::rec_server::RecorderStatus if (hdf5_recorder_item == nullptr) continue; bool update_needed_hdf5_rec = false; - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateStillOnline (recorder_still_online); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updatePid (pid); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateInfoLastCommandResponse(client_job_status.second.info_last_command_response_); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateLength ({ client_job_status.second.job_status_.rec_hdf5_status_.total_length_, client_job_status.second.job_status_.rec_hdf5_status_.total_frame_count_ }); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateUnflushedFrameCount (client_job_status.second.job_status_.rec_hdf5_status_.unflushed_frame_count_); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateState (client_job_status.second.job_status_.state_); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateUploadStatus (client_job_status.second.job_status_.upload_status_); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateInfo (client_job_status.second.job_status_.rec_hdf5_status_.info_); - update_needed_hdf5_rec = update_needed_hdf5_rec || hdf5_recorder_item->updateIsDeleted (is_deleted); + update_needed_hdf5_rec = hdf5_recorder_item->updateStillOnline (recorder_still_online) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updatePid (pid) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateInfoLastCommandResponse(client_job_status.second.info_last_command_response_) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateLength ({ client_job_status.second.job_status_.rec_hdf5_status_.total_length_, client_job_status.second.job_status_.rec_hdf5_status_.total_frame_count_ }) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateUnflushedFrameCount (client_job_status.second.job_status_.rec_hdf5_status_.unflushed_frame_count_) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateState (client_job_status.second.job_status_.state_) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateUploadStatus (client_job_status.second.job_status_.upload_status_) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateInfo (client_job_status.second.job_status_.rec_hdf5_status_.info_) || update_needed_hdf5_rec; + update_needed_hdf5_rec = hdf5_recorder_item->updateIsDeleted (is_deleted) || update_needed_hdf5_rec; if (update_needed_hdf5_rec) { @@ -216,13 +216,13 @@ void JobHistoryModel::setRecorderStatuses(const eCAL::rec_server::RecorderStatus } bool update_needed_addon = false; - update_needed_addon = update_needed_addon || addon_item->updateStillOnline (addon_still_online); - update_needed_addon = update_needed_addon || addon_item->updatePid (pid); - update_needed_addon = update_needed_addon || addon_item->updateLength ({std::chrono::steady_clock::duration(0), addon_id_status_pair.second.total_frame_count_ }); - update_needed_addon = update_needed_addon || addon_item->updateUnflushedFrameCount(addon_id_status_pair.second.unflushed_frame_count_); - update_needed_addon = update_needed_addon || addon_item->updateState (addon_state); - update_needed_addon = update_needed_addon || addon_item->updateInfo (addon_id_status_pair.second.info_); - update_needed_addon = update_needed_addon || addon_item->updateIsDeleted (is_deleted); + update_needed_addon = addon_item->updateStillOnline (addon_still_online) || update_needed_addon; + update_needed_addon = addon_item->updatePid (pid) || update_needed_addon; + update_needed_addon = addon_item->updateLength ({std::chrono::steady_clock::duration(0), addon_id_status_pair.second.total_frame_count_ }) || update_needed_addon; + update_needed_addon = addon_item->updateUnflushedFrameCount(addon_id_status_pair.second.unflushed_frame_count_) || update_needed_addon; + update_needed_addon = addon_item->updateState (addon_state) || update_needed_addon; + update_needed_addon = addon_item->updateInfo (addon_id_status_pair.second.info_) || update_needed_addon; + update_needed_addon = addon_item->updateIsDeleted (is_deleted) || update_needed_addon; if (update_needed_addon) { diff --git a/app/rec/rec_gui/src/widgets/recording_history_widget/recording_history_widget.cpp b/app/rec/rec_gui/src/widgets/recording_history_widget/recording_history_widget.cpp index c88ce63c0a..80ce5dc306 100644 --- a/app/rec/rec_gui/src/widgets/recording_history_widget/recording_history_widget.cpp +++ b/app/rec/rec_gui/src/widgets/recording_history_widget/recording_history_widget.cpp @@ -31,7 +31,7 @@ #include -#include +#include //////////////////////////////////////////////// // Constructor & Destructor diff --git a/app/rec/rec_gui/src/widgets/wait_for_shutdown_dialog/wait_for_shutdown_dialog.cpp b/app/rec/rec_gui/src/widgets/wait_for_shutdown_dialog/wait_for_shutdown_dialog.cpp index 5aca3591dd..21bbfad48c 100644 --- a/app/rec/rec_gui/src/widgets/wait_for_shutdown_dialog/wait_for_shutdown_dialog.cpp +++ b/app/rec/rec_gui/src/widgets/wait_for_shutdown_dialog/wait_for_shutdown_dialog.cpp @@ -373,10 +373,10 @@ bool WaitForShutdownDialog::updateAllFields() auto job_history = QEcalRec::instance()->jobHistory(); bool safe_to_exit = true; - safe_to_exit = safe_to_exit && updateWaitForFlushing(); - safe_to_exit = safe_to_exit && updateBuiltInRecorderUploading(job_history); - safe_to_exit = safe_to_exit && updateBuiltInFtpServer(); - safe_to_exit = safe_to_exit && updateNonUploadedMeasurements(); + safe_to_exit = updateWaitForFlushing() && safe_to_exit; + safe_to_exit = updateBuiltInRecorderUploading(job_history) && safe_to_exit; + safe_to_exit = updateBuiltInFtpServer() && safe_to_exit; + safe_to_exit = updateNonUploadedMeasurements() && safe_to_exit; updateItIsSafeToExit(safe_to_exit); diff --git a/app/rec/rec_server_cli/CMakeLists.txt b/app/rec/rec_server_cli/CMakeLists.txt index 686297e918..7eba07adf5 100644 --- a/app/rec/rec_server_cli/CMakeLists.txt +++ b/app/rec/rec_server_cli/CMakeLists.txt @@ -83,7 +83,7 @@ target_compile_definitions(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE tclap::tclap termcolor::termcolor eCAL::rec_server_core diff --git a/app/rec/rec_server_cli/src/commands/command.cpp b/app/rec/rec_server_cli/src/commands/command.cpp index 1d3fd97ad2..dd05a7aebc 100644 --- a/app/rec/rec_server_cli/src/commands/command.cpp +++ b/app/rec/rec_server_cli/src/commands/command.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ namespace eCAL { remote_ecalsys_service->SetHostName(hostname); - eCAL::ServiceResponseVecT service_response_vec; + eCAL::v5::ServiceResponseVecT service_response_vec; constexpr int timeout_ms = 1000; if (remote_ecalsys_service->Call(method_name, request.SerializeAsString(), timeout_ms, &service_response_vec)) diff --git a/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp b/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp index d171fff4a7..016939e218 100644 --- a/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp +++ b/app/rec/rec_server_cli/src/ecal_rec_server_cli.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include @@ -144,6 +144,9 @@ std::unique_ptr record_command; int main(int argc, char** argv) { #ifdef WIN32 + (void)argc; // suppress unused warning + (void)argv; // suppress unused warning + EcalUtils::WinCpChanger win_cp_changer(CP_UTF8); // The WinCpChanger will set the Codepage back to the original, once destroyed #endif // WIN32 @@ -330,14 +333,14 @@ int main(int argc, char** argv) /************************************************************************/ if (remote_control_arg.isSet()) // Remote-control-mode { - eCAL::Initialize(argc, argv, "eCALRec-Remote", eCAL::Init::All); - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + eCAL::Initialize("eCALRec-Remote", eCAL::Init::All); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); remote_rec_server_service = std::make_shared>(); } else // Non-remote control mode { - eCAL::Initialize(argc, argv, "eCALRec", eCAL::Init::All); + eCAL::Initialize("eCALRec", eCAL::Init::All); rec_server_instance = std::make_shared(); @@ -1568,9 +1571,9 @@ bool IsRecorderBusy(bool print_status) std::cout << "Waiting for the following events:" << std::endl; bool still_busy = false; - still_busy = still_busy || IsAnyClientFlushing (print_status); - still_busy = still_busy || IsAnyClientUploading (print_status); - still_busy = still_busy || IsBuiltInFtpServerBusy(print_status); + still_busy = IsAnyClientFlushing (print_status) || still_busy; + still_busy = IsAnyClientUploading (print_status) || still_busy; + still_busy = IsBuiltInFtpServerBusy(print_status) || still_busy; if (print_status && !still_busy) { diff --git a/app/rec/rec_server_core/CMakeLists.txt b/app/rec/rec_server_core/CMakeLists.txt index 6f5225d9e3..8092dc0a1e 100644 --- a/app/rec/rec_server_core/CMakeLists.txt +++ b/app/rec/rec_server_core/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2018 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -68,7 +68,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE tinyxml2::tinyxml2 protobuf::libprotobuf - eCAL::core + eCAL::protobuf_core eCAL::app_pb ThreadingUtils Threads::Threads diff --git a/app/rec/rec_server_core/include/rec_server_core/ecalstate_helpers.h b/app/rec/rec_server_core/include/rec_server_core/ecalstate_helpers.h index 403cddb084..e5c04437cc 100644 --- a/app/rec/rec_server_core/include/rec_server_core/ecalstate_helpers.h +++ b/app/rec/rec_server_core/include/rec_server_core/ecalstate_helpers.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,7 @@ #pragma once -#include +#include #include "status.h" #include "rec_server_config.h" @@ -27,6 +27,6 @@ namespace eCAL { namespace rec_server { - std::pair GetProcessSeverity(const eCAL::rec_server::RecServerStatus& rec_server_status, const std::map& rec_server_config); + std::pair GetProcessSeverity(const eCAL::rec_server::RecServerStatus& rec_server_status, const std::map& rec_server_config); } } \ No newline at end of file diff --git a/app/rec/rec_server_core/include/rec_server_core/rec_server_types.h b/app/rec/rec_server_core/include/rec_server_core/rec_server_types.h index 883e03636b..5dd1300202 100644 --- a/app/rec/rec_server_core/include/rec_server_core/rec_server_types.h +++ b/app/rec/rec_server_core/include/rec_server_core/rec_server_types.h @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff --git a/app/rec/rec_server_core/src/ecalstate_helpers.cpp b/app/rec/rec_server_core/src/ecalstate_helpers.cpp index c4cdfd80bc..8ac5859030 100644 --- a/app/rec/rec_server_core/src/ecalstate_helpers.cpp +++ b/app/rec/rec_server_core/src/ecalstate_helpers.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,14 +25,14 @@ namespace eCAL { namespace rec_server { - std::pair GetProcessSeverity(const eCAL::rec_server::RecServerStatus& rec_server_status, const std::map& enabled_rec_clients) + std::pair GetProcessSeverity(const eCAL::rec_server::RecServerStatus& rec_server_status, const std::map& enabled_rec_clients) { - eCAL_Process_eSeverity severity(eCAL_Process_eSeverity::proc_sev_healthy); + eCAL::Process::eSeverity severity(eCAL::Process::eSeverity::healthy); std::string state_string; if(!rec_server_status.activated_) { - severity = std::max(severity, eCAL_Process_eSeverity::proc_sev_warning); + severity = std::max(severity, eCAL::Process::eSeverity::warning); state_string = "Not activated"; } else @@ -77,7 +77,7 @@ namespace eCAL if ((not_connected_hosts > 0) || (not_connected_addons > 0)) { - severity = std::max(severity, eCAL_Process_eSeverity::proc_sev_critical); + severity = std::max(severity, eCAL::Process::eSeverity::critical); state_string += ", Failed connecting to "; if (not_connected_hosts > 0) { @@ -92,7 +92,7 @@ namespace eCAL } else if (connected_hosts == 0) { - severity = std::max(severity, eCAL_Process_eSeverity::proc_sev_warning); + severity = std::max(severity, eCAL::Process::eSeverity::warning); state_string += ", No clients"; } else diff --git a/app/rec/rec_server_core/src/monitoring_thread.cpp b/app/rec/rec_server_core/src/monitoring_thread.cpp index 9db3eab99c..f351b86c26 100644 --- a/app/rec/rec_server_core/src/monitoring_thread.cpp +++ b/app/rec/rec_server_core/src/monitoring_thread.cpp @@ -125,19 +125,22 @@ namespace eCAL // Update topic list for (const auto& topic : monitoring_pb.topics()) { + // Create combined encoding:type type (to be fully compatible to old behavior) + std::string combined_enc_type = eCAL::Util::CombinedTopicEncodingAndType(topic.tdatatype().encoding(), topic.tdatatype().name()); + auto topic_info_map_it = topic_info_map_.find(topic.tname()); if (topic_info_map_it != topic_info_map_.end()) { // Only update the values if there are information available - if (!topic.ttype().empty() || !topic.tdesc().empty()) + if (!combined_enc_type.empty() || !topic.tdatatype().name().empty()) { - topic_info_map_it->second.type_ = topic.ttype(); + topic_info_map_it->second.type_ = combined_enc_type; } } else { // Create a new topic entry - topic_info_map_.emplace(topic.tname(), eCAL::rec_server::TopicInfo(topic.ttype())); + topic_info_map_.emplace(topic.tname(), eCAL::rec_server::TopicInfo(combined_enc_type)); topic_info_map_it = topic_info_map_.find(topic.tname()); } diff --git a/app/rec/rec_server_core/src/rec_server_impl.cpp b/app/rec/rec_server_core/src/rec_server_impl.cpp index 30962b668d..bf9cf2e596 100644 --- a/app/rec/rec_server_core/src/rec_server_impl.cpp +++ b/app/rec/rec_server_core/src/rec_server_impl.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,7 +60,7 @@ namespace eCAL settings_.ClearHostFilter(); // There is no global host filter // Initialize eCAL - eCAL::Initialize(0, nullptr, "", eCAL::Init::Default | eCAL::Init::Monitoring); + eCAL::Initialize("eCALRec-Server", eCAL::Init::Default | eCAL::Init::Monitoring); // Start FTP Server ftp_server_->start(5); diff --git a/app/rec/rec_server_core/src/recorder/remote_recorder.cpp b/app/rec/rec_server_core/src/recorder/remote_recorder.cpp index c8eccde50a..2b227cd1e7 100644 --- a/app/rec/rec_server_core/src/recorder/remote_recorder.cpp +++ b/app/rec/rec_server_core/src/recorder/remote_recorder.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -669,7 +669,7 @@ namespace eCAL { // The target (i.e. the hostname) has already been set in the Constructor. - eCAL::ServiceResponseVecT service_response_vec; + eCAL::v5::ServiceResponseVecT service_response_vec; constexpr int timeout_ms = 1000; if (recorder_service_.Call(method_name, request.SerializeAsString(), timeout_ms, &service_response_vec)) { diff --git a/app/rec/rec_tests/rec_rpc_tests/src/external_ecal_rec.cpp b/app/rec/rec_tests/rec_rpc_tests/src/external_ecal_rec.cpp index a10e85d405..9e7a215725 100644 --- a/app/rec/rec_tests/rec_rpc_tests/src/external_ecal_rec.cpp +++ b/app/rec/rec_tests/rec_rpc_tests/src/external_ecal_rec.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ ExternalEcalRecInstance::ExternalEcalRecInstance(bool gui) { ecal_rec_cli_instance_lock.lock(); - eCAL::Initialize({}, "Ecal Rec Tester"); + eCAL::Initialize("Ecal Rec Tester"); remote_rec_server_service = std::make_shared>(); remote_rec_server_service->SetHostName(eCAL::Process::GetHostName()); @@ -46,12 +46,12 @@ ExternalEcalRecInstance::ExternalEcalRecInstance(bool gui) if (gui) { std::cout << "Starting " << "\"" << ECAL_REC_GUI_PATH << "\"" << std::endl; - pid = eCAL::Process::StartProcess(ECAL_REC_GUI_PATH, "", "", false, eCAL_Process_eStartMode::proc_smode_minimized, false); + pid = eCAL::Process::StartProcess(ECAL_REC_GUI_PATH, "", "", false, eCAL::Process::eStartMode::minimized, false); } else { std::cout << "Starting " << "\"" << ECAL_REC_CLI_PATH << "\"" << std::endl; - pid = eCAL::Process::StartProcess(ECAL_REC_CLI_PATH, "--interactive-dont-exit --no-default", "", false, eCAL_Process_eStartMode::proc_smode_hidden, false); + pid = eCAL::Process::StartProcess(ECAL_REC_CLI_PATH, "--interactive-dont-exit --no-default", "", false, eCAL::Process::eStartMode::hidden, false); } if (pid != 0) @@ -120,7 +120,7 @@ eCAL::rec::Error ExternalEcalRecInstance::GetConfigViaRpc(eCAL::rec_server::RecS eCAL::rec::Error ExternalEcalRecInstance::GetConfigViaRpc(eCAL::pb::rec_server::RecServerConfig& config_pb_output) { eCAL::pb::rec_server::GenericRequest request; - eCAL::ServiceResponseVecT service_response_vec; + eCAL::v5::ServiceResponseVecT service_response_vec; constexpr int timeout_ms = 1000; @@ -143,7 +143,7 @@ eCAL::rec::Error ExternalEcalRecInstance::SetConfigViaRpc(const eCAL::rec_server eCAL::rec::Error ExternalEcalRecInstance::SetConfigViaRpc(const eCAL::pb::rec_server::RecServerConfig& config_pb) { - eCAL::ServiceResponseVecT service_response_vec; + eCAL::v5::ServiceResponseVecT service_response_vec; constexpr int timeout_ms = 1000; diff --git a/app/rec/rec_tests/rec_rpc_tests/src/rec_cli_test.cpp b/app/rec/rec_tests/rec_rpc_tests/src/rec_cli_test.cpp index 2dbc826a6f..13d6d56e67 100644 --- a/app/rec/rec_tests/rec_rpc_tests/src/rec_cli_test.cpp +++ b/app/rec/rec_tests/rec_rpc_tests/src/rec_cli_test.cpp @@ -149,7 +149,7 @@ std::vector getRpcConfigTestcases() return testcases; } -TEST(EcalRecCli, NoDefault) +TEST(app, EcalRecCli_NoDefault) { eCAL::rec_server::RecServerConfig config; @@ -159,7 +159,7 @@ TEST(EcalRecCli, NoDefault) EXPECT_EQ(config, eCAL::rec_server::RecServerConfig()); } -TEST(EcalRecCli, SetConfigViaRPC) +TEST(app, EcalRecCli_SetConfigViaRPC) { auto test_cases = getRpcConfigTestcases(); auto rec = ExternalEcalRecInstance(); @@ -177,7 +177,7 @@ TEST(EcalRecCli, SetConfigViaRPC) } } -TEST(EcalRecGui, SetConfigViaRPC) +TEST(app, EcalRecGui_SetConfigViaRPC) { auto test_cases = getRpcConfigTestcases(); auto rec = ExternalEcalRecInstance(true); diff --git a/app/sys/sys_cli/CMakeLists.txt b/app/sys/sys_cli/CMakeLists.txt index 023a7cf6f4..bdc1929246 100644 --- a/app/sys/sys_cli/CMakeLists.txt +++ b/app/sys/sys_cli/CMakeLists.txt @@ -70,7 +70,7 @@ target_compile_definitions(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE tclap::tclap termcolor::termcolor eCAL::sys_core diff --git a/app/sys/sys_cli/src/commands/command.cpp b/app/sys/sys_cli/src/commands/command.cpp index e0e0e4827e..0c90bb4832 100644 --- a/app/sys/sys_cli/src/commands/command.cpp +++ b/app/sys/sys_cli/src/commands/command.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ namespace eCAL { remote_ecalsys_service->SetHostName(hostname); - eCAL::ServiceResponseVecT service_response_vec; + eCAL::v5::ServiceResponseVecT service_response_vec; constexpr int timeout_ms = 1000; if (remote_ecalsys_service->Call(method_name, request.SerializeAsString(), timeout_ms, &service_response_vec)) diff --git a/app/sys/sys_cli/src/commands/command.h b/app/sys/sys_cli/src/commands/command.h index 2ce60c050b..61e3a0b2a0 100644 --- a/app/sys/sys_cli/src/commands/command.h +++ b/app/sys/sys_cli/src/commands/command.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include #include -#include +#include #ifdef _MSC_VER #pragma warning(push) diff --git a/app/sys/sys_cli/src/commands/helpers.h b/app/sys/sys_cli/src/commands/helpers.h index 77cfb15711..f5e13a6bcc 100644 --- a/app/sys/sys_cli/src/commands/helpers.h +++ b/app/sys/sys_cli/src/commands/helpers.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ #include #include -#include +#include #ifdef _MSC_VER #pragma warning(push) diff --git a/app/sys/sys_cli/src/commands/list.cpp b/app/sys/sys_cli/src/commands/list.cpp index 8fc98c9c8f..04814a62ed 100644 --- a/app/sys/sys_cli/src/commands/list.cpp +++ b/app/sys/sys_cli/src/commands/list.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -256,7 +256,7 @@ namespace eCAL size_t longest_state = header_data[6].size(); std::vector> string_data; - std::vector serverity_data; + std::vector serverity_data; string_data .reserve(task_list.size()); serverity_data.reserve(task_list.size()); @@ -284,16 +284,16 @@ namespace eCAL switch (monitoring_state.severity) { - case eCAL_Process_eSeverity::proc_sev_healthy: + case eCAL::Process::eSeverity::healthy: state_ss << termcolor::on_green << state << termcolor::reset; break; - case eCAL_Process_eSeverity::proc_sev_warning: + case eCAL::Process::eSeverity::warning: state_ss << termcolor::on_yellow << state << termcolor::reset; break; - case eCAL_Process_eSeverity::proc_sev_critical: + case eCAL::Process::eSeverity::critical: state_ss << termcolor::on_red << state << termcolor::reset; break; - case eCAL_Process_eSeverity::proc_sev_failed: + case eCAL::Process::eSeverity::failed: state_ss << termcolor::on_magenta << state << termcolor::reset; break; default: @@ -353,16 +353,16 @@ namespace eCAL switch (serverity_data[i]) { - case eCAL_Process_eSeverity::proc_sev_healthy: + case eCAL::Process::eSeverity::healthy: std::cout << termcolor::on_green; break; - case eCAL_Process_eSeverity::proc_sev_warning: + case eCAL::Process::eSeverity::warning: std::cout << termcolor::on_yellow; break; - case eCAL_Process_eSeverity::proc_sev_critical: + case eCAL::Process::eSeverity::critical: std::cout << termcolor::on_red; break; - case eCAL_Process_eSeverity::proc_sev_failed: + case eCAL::Process::eSeverity::failed: std::cout << termcolor::on_magenta; break; default: @@ -382,16 +382,16 @@ namespace eCAL std::string visibility_string; switch (task->GetVisibility()) { - case eCAL_Process_eStartMode::proc_smode_hidden: + case eCAL::Process::eStartMode::hidden: visibility_string = "hidden"; break; - case eCAL_Process_eStartMode::proc_smode_minimized: + case eCAL::Process::eStartMode::minimized: visibility_string = "minimized"; break; - case eCAL_Process_eStartMode::proc_smode_maximized: + case eCAL::Process::eStartMode::maximized: visibility_string = "maximized"; break; - case eCAL_Process_eStartMode::proc_smode_normal: + case eCAL::Process::eStartMode::normal: visibility_string = "normal"; break; default: @@ -424,23 +424,23 @@ namespace eCAL switch (task_state.severity) { - case eCAL_Process_eSeverity::proc_sev_healthy: + case eCAL::Process::eSeverity::healthy: std::cout << termcolor::on_green; break; - case eCAL_Process_eSeverity::proc_sev_warning: + case eCAL::Process::eSeverity::warning: std::cout << termcolor::on_yellow; break; - case eCAL_Process_eSeverity::proc_sev_critical: + case eCAL::Process::eSeverity::critical: std::cout << termcolor::on_red; break; - case eCAL_Process_eSeverity::proc_sev_failed: + case eCAL::Process::eSeverity::failed: std::cout << termcolor::on_magenta; break; default: break; } - std::cout << "State: " << (task_state.severity == eCAL_Process_eSeverity::proc_sev_unknown ? state : state + " " + level) << std::endl; + std::cout << "State: " << (task_state.severity == eCAL::Process::eSeverity::unknown ? state : state + " " + level) << std::endl; std::cout << termcolor::reset; std::cout << "Info: " << task_state.info << std::endl; diff --git a/app/sys/sys_cli/src/ecalsys_cli.cpp b/app/sys/sys_cli/src/ecalsys_cli.cpp index 5534dba572..5a042a4256 100644 --- a/app/sys/sys_cli/src/ecalsys_cli.cpp +++ b/app/sys/sys_cli/src/ecalsys_cli.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -237,15 +237,15 @@ int main(int argc, char** argv) /************************************************************************/ if (remote_control_arg.isSet()) // Remote-control-mode { - eCAL::Initialize(0, nullptr, "eCALSys-Remote", eCAL::Init::All); - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + eCAL::Initialize("eCALSys-Remote", eCAL::Init::All); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); remote_ecalsys_service = std::make_shared>(); } else // Non-remote control mode { - eCAL::Initialize(0, nullptr, "eCALSys", eCAL::Init::All); - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + eCAL::Initialize("eCALSys", eCAL::Init::All); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); ecalsys_instance = std::make_shared(); diff --git a/app/sys/sys_client_cli/CMakeLists.txt b/app/sys/sys_client_cli/CMakeLists.txt index c18eeaa3ee..1a90d9ae32 100644 --- a/app/sys/sys_client_cli/CMakeLists.txt +++ b/app/sys/sys_client_cli/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2020 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -39,11 +39,11 @@ ecal_add_app_console(${PROJECT_NAME} ${source_files} ${win_src}) create_targets_protobuf() -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE spdlog::spdlog tclap::tclap protobuf::libprotobuf - eCAL::core + eCAL::protobuf_core eCAL::core_pb eCAL::app_pb eCAL::sys_client_core diff --git a/app/sys/sys_client_cli/src/ecal_sys_client_cli.cpp b/app/sys/sys_client_cli/src/ecal_sys_client_cli.cpp index c965f4e0e5..60d5480556 100644 --- a/app/sys/sys_client_cli/src/ecal_sys_client_cli.cpp +++ b/app/sys/sys_client_cli/src/ecal_sys_client_cli.cpp @@ -113,7 +113,7 @@ int main(int argc, char** argv) logger->info("eCAL Sys Client was started with " + accept_security_risk_arg.longID() + ". Not displaying security warning."); } - eCAL::Initialize(argc, argv, "eCALSysClient", eCAL::Init::Default | eCAL::Init::Monitoring); + eCAL::Initialize("eCALSysClient", eCAL::Init::Default | eCAL::Init::Monitoring); // Print System information std::string config_string; diff --git a/app/sys/sys_client_cli/src/ecal_sys_client_service.cpp b/app/sys/sys_client_cli/src/ecal_sys_client_service.cpp index d10fa69572..1ba0678276 100644 --- a/app/sys/sys_client_cli/src/ecal_sys_client_service.cpp +++ b/app/sys/sys_client_cli/src/ecal_sys_client_service.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include EcalSysClientService::EcalSysClientService() {} diff --git a/app/sys/sys_client_core/include/sys_client_core/ecal_sys_client_logger.h b/app/sys/sys_client_core/include/sys_client_core/ecal_sys_client_logger.h index bd437716c4..cb914148ff 100644 --- a/app/sys/sys_client_core/include/sys_client_core/ecal_sys_client_logger.h +++ b/app/sys/sys_client_core/include/sys_client_core/ecal_sys_client_logger.h @@ -52,7 +52,7 @@ namespace eCAL static const int MAXIMUM_ROTATING_FILES = 5; static const int FIVE_MEGABYTES = 5 * 1024 * 1024; - auto ecal_data_path = eCAL::Util::GeteCALLogPath(); + auto ecal_data_path = eCAL::Util::GeteCALLogDir(); std::string log_filename = ecal_data_path + ecal_sys_client + ".log"; // create console logger and rotating file logger with maximum size 5MB and maximum 5 rotating files diff --git a/app/sys/sys_client_core/include/sys_client_core/proto_helpers.h b/app/sys/sys_client_core/include/sys_client_core/proto_helpers.h index 77676cd38b..1201588ec8 100644 --- a/app/sys/sys_client_core/include/sys_client_core/proto_helpers.h +++ b/app/sys/sys_client_core/include/sys_client_core/proto_helpers.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ #include "runner.h" #include "task.h" -#include +#include #include @@ -47,7 +47,7 @@ namespace eCAL void FromProtobuf(const eCAL::pb::sys_client::Task& task_pb, eCAL::sys_client::Task& task); void FromProtobuf(const eCAL::pb::sys_client::Runner& runner_pb, eCAL::sys_client::Runner& runner); - void FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb, eCAL_Process_eStartMode& window_mode); + void FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb, eCAL::Process::eStartMode& window_mode); void FromProtobuf(const eCAL::pb::sys_client::StartTaskParameters& start_task_param_pb, StartTaskParameters& start_task_param); void FromProtobuf(const eCAL::pb::sys_client::StartTaskRequest& start_task_list_pb, std::vector& start_task_list); void FromProtobuf(const eCAL::pb::sys_client::StopTaskParameters& stop_task_param_pb, StopTaskParameters& stop_task_param); @@ -58,7 +58,7 @@ namespace eCAL eCAL::sys_client::Task FromProtobuf(const eCAL::pb::sys_client::Task& task_pb); eCAL::sys_client::Runner FromProtobuf(const eCAL::pb::sys_client::Runner& runner_pb); - eCAL_Process_eStartMode FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb); + eCAL::Process::eStartMode FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb); StartTaskParameters FromProtobuf(const eCAL::pb::sys_client::StartTaskParameters& start_task_param_pb); std::vector FromProtobuf(const eCAL::pb::sys_client::StartTaskRequest& start_task_list_pb); StopTaskParameters FromProtobuf(const eCAL::pb::sys_client::StopTaskParameters& stop_task_param_pb); @@ -73,7 +73,7 @@ namespace eCAL void ToProtobuf(eCAL::pb::sys_client::Task& task_pb, const eCAL::sys_client::Task& task); void ToProtobuf(eCAL::pb::sys_client::Runner& runner_pb, const eCAL::sys_client::Runner& runner); - void ToProtobuf(eCAL::pb::sys_client::WindowMode& window_mode_pb, const eCAL_Process_eStartMode window_mode); + void ToProtobuf(eCAL::pb::sys_client::WindowMode& window_mode_pb, const eCAL::Process::eStartMode window_mode); void ToProtobuf(eCAL::pb::sys_client::StartTaskParameters& start_task_param_pb, const StartTaskParameters& start_task_param); void ToProtobuf(eCAL::pb::sys_client::StartTaskRequest& start_task_list_pb, const std::vector& start_task_list); void ToProtobuf(eCAL::pb::sys_client::StopTaskParameters& stop_task_param_pb, const StopTaskParameters& stop_task_param); @@ -84,7 +84,7 @@ namespace eCAL eCAL::pb::sys_client::Task ToProtobuf(const eCAL::sys_client::Task& task); eCAL::pb::sys_client::Runner ToProtobuf(const eCAL::sys_client::Runner& runner); - eCAL::pb::sys_client::WindowMode ToProtobuf(const eCAL_Process_eStartMode window_mode); + eCAL::pb::sys_client::WindowMode ToProtobuf(const eCAL::Process::eStartMode window_mode); eCAL::pb::sys_client::StartTaskParameters ToProtobuf(const StartTaskParameters& start_task_param); eCAL::pb::sys_client::StartTaskRequest ToProtobuf(const std::vector& start_task_list); eCAL::pb::sys_client::StopTaskParameters ToProtobuf(const StopTaskParameters& stop_task_param); diff --git a/app/sys/sys_client_core/include/sys_client_core/task.h b/app/sys/sys_client_core/include/sys_client_core/task.h index 6a80db254c..9077fd2330 100644 --- a/app/sys/sys_client_core/include/sys_client_core/task.h +++ b/app/sys/sys_client_core/include/sys_client_core/task.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ #include -#include +#include #include #include @@ -42,12 +42,12 @@ namespace eCAL struct StartTaskParameters { StartTaskParameters() - : window_mode (eCAL_Process_eStartMode::proc_smode_normal) + : window_mode (eCAL::Process::eStartMode::normal) , create_console(false) {} Task task; - eCAL_Process_eStartMode window_mode; + eCAL::Process::eStartMode window_mode; bool create_console; }; diff --git a/app/sys/sys_client_core/src/ecal_sys_client.cpp b/app/sys/sys_client_core/src/ecal_sys_client.cpp index fa56d6d98c..f0ea1efe84 100644 --- a/app/sys/sys_client_core/src/ecal_sys_client.cpp +++ b/app/sys/sys_client_core/src/ecal_sys_client.cpp @@ -28,8 +28,8 @@ #pragma warning(pop) #endif -#include -#include +#include +#include #include #include diff --git a/app/sys/sys_client_core/src/proto_helpers.cpp b/app/sys/sys_client_core/src/proto_helpers.cpp index 1e13ac793a..655bb9e977 100644 --- a/app/sys/sys_client_core/src/proto_helpers.cpp +++ b/app/sys/sys_client_core/src/proto_helpers.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ namespace eCAL runner.default_task_dir = runner_pb.default_task_dir(); } - void FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb, eCAL_Process_eStartMode& window_mode) + void FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb, eCAL::Process::eStartMode& window_mode) { window_mode = FromProtobuf(window_mode_pb); } @@ -132,18 +132,18 @@ namespace eCAL return runner; } - eCAL_Process_eStartMode FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb) + eCAL::Process::eStartMode FromProtobuf(const eCAL::pb::sys_client::WindowMode& window_mode_pb) { switch (window_mode_pb) { case eCAL::pb::sys_client::WindowMode::hidden: - return eCAL_Process_eStartMode::proc_smode_hidden; + return eCAL::Process::eStartMode::hidden; case eCAL::pb::sys_client::WindowMode::minimized: - return eCAL_Process_eStartMode::proc_smode_minimized; + return eCAL::Process::eStartMode::minimized; case eCAL::pb::sys_client::WindowMode::maximized: - return eCAL_Process_eStartMode::proc_smode_maximized; + return eCAL::Process::eStartMode::maximized; default: - return eCAL_Process_eStartMode::proc_smode_normal; + return eCAL::Process::eStartMode::normal; } } @@ -216,7 +216,7 @@ namespace eCAL runner_pb.set_default_task_dir(runner.default_task_dir); } - void ToProtobuf(eCAL::pb::sys_client::WindowMode& window_mode_pb, const eCAL_Process_eStartMode window_mode) + void ToProtobuf(eCAL::pb::sys_client::WindowMode& window_mode_pb, const eCAL::Process::eStartMode window_mode) { window_mode_pb = ToProtobuf(window_mode); } @@ -298,15 +298,15 @@ namespace eCAL return output; } - eCAL::pb::sys_client::WindowMode ToProtobuf(const eCAL_Process_eStartMode window_mode) + eCAL::pb::sys_client::WindowMode ToProtobuf(const eCAL::Process::eStartMode window_mode) { switch (window_mode) { - case eCAL_Process_eStartMode::proc_smode_hidden: + case eCAL::Process::eStartMode::hidden: return eCAL::pb::sys_client::WindowMode::hidden; - case eCAL_Process_eStartMode::proc_smode_minimized: + case eCAL::Process::eStartMode::minimized: return eCAL::pb::sys_client::WindowMode::minimized; - case eCAL_Process_eStartMode::proc_smode_maximized: + case eCAL::Process::eStartMode::maximized: return eCAL::pb::sys_client::WindowMode::maximized; default: return eCAL::pb::sys_client::WindowMode::normal; diff --git a/app/sys/sys_core/CMakeLists.txt b/app/sys/sys_core/CMakeLists.txt index 707178a715..7f36ab17f5 100644 --- a/app/sys/sys_core/CMakeLists.txt +++ b/app/sys/sys_core/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2020 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -91,7 +91,7 @@ target_link_libraries(${PROJECT_NAME} tinyxml2::tinyxml2 spdlog::spdlog protobuf::libprotobuf - eCAL::core + eCAL::protobuf_core eCAL::core_pb eCAL::app_pb EcalParser diff --git a/app/sys/sys_core/include/ecalsys/ecal_sys_logger.h b/app/sys/sys_core/include/ecalsys/ecal_sys_logger.h index d163936905..5b25e3fa25 100644 --- a/app/sys/sys_core/include/ecalsys/ecal_sys_logger.h +++ b/app/sys/sys_core/include/ecalsys/ecal_sys_logger.h @@ -49,7 +49,7 @@ class EcalSysLogger static const int MAXIMUM_ROTATING_FILES = 5; static const int FIVE_MEGABYTES = 5 * 1024 * 1024; - auto ecal_data_path = eCAL::Util::GeteCALLogPath(); + auto ecal_data_path = eCAL::Util::GeteCALLogDir(); std::string log_filename = ecal_data_path + ECAL_SYS_LIB_NAME + ".log"; // create console logger and rotating file logger with maximum size 5MB and maximum 5 rotating files diff --git a/app/sys/sys_core/include/ecalsys/proto_helpers.h b/app/sys/sys_core/include/ecalsys/proto_helpers.h index 6a693bd20a..2473fe7699 100644 --- a/app/sys/sys_core/include/ecalsys/proto_helpers.h +++ b/app/sys/sys_core/include/ecalsys/proto_helpers.h @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/app/sys/sys_core/include/ecalsys/task/ecal_sys_task.h b/app/sys/sys_core/include/ecalsys/task/ecal_sys_task.h index 6b6cd82489..02339e21e6 100644 --- a/app/sys/sys_core/include/ecalsys/task/ecal_sys_task.h +++ b/app/sys/sys_core/include/ecalsys/task/ecal_sys_task.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -85,7 +85,7 @@ class EcalSysTask std::chrono::nanoseconds GetTimeoutAfterStart(); /** @return The configured startup-visibility when starting this Task on a Windows host.*/ - eCAL_Process_eStartMode GetVisibility(); + eCAL::Process::eStartMode GetVisibility(); /** @return The configured arguments that will be given to the task when being started.*/ std::string GetCommandLineArguments(); @@ -125,7 +125,7 @@ class EcalSysTask void SetTimeoutAfterStart (std::chrono::nanoseconds timeout); /** @brief Sets the visibility when starting the task on a Windows machine. */ - void SetVisibility (eCAL_Process_eStartMode visibility); + void SetVisibility (eCAL::Process::eStartMode visibility); /** @brief Sets the arguments that will be given to the task when being started. */ void SetCommandLineArguments (std::string command_line_args); @@ -290,7 +290,7 @@ class EcalSysTask std::string m_working_directory; /**< The working directory when starting the process */ unsigned int m_launch_order; /**< The order in which tasks will start when started simultaneously. */ std::chrono::nanoseconds m_timeout_after_start; /**< After being started, the task may wait a certain amount of time and thus delay the start of other tasks that are started at the same time but have a higher launch order number.*/ - eCAL_Process_eStartMode m_visibility; /**< The visibility when starting this task on a Windows system */ + eCAL::Process::eStartMode m_visibility; /**< The visibility when starting this task on a Windows system */ bool m_monitoring_enabled; /**< When true, this task will be monitored by the monitoring thread and the task state will be set accordingly. This is a requirement for the restart-by-severity functionality.*/ bool m_restart_by_severity_enabled; /**< When true, the task will be killed and restarted if it's severity reaches a certain state. */ diff --git a/app/sys/sys_core/include/ecalsys/task/task_state.h b/app/sys/sys_core/include/ecalsys/task/task_state.h index 367980088d..0e0f2efeb8 100644 --- a/app/sys/sys_core/include/ecalsys/task/task_state.h +++ b/app/sys/sys_core/include/ecalsys/task/task_state.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,16 +28,16 @@ class TaskState { public: - eCAL_Process_eSeverity severity; /**< The severity (Unknown, Healthy, Warning, Critical, Failed) */ - eCAL_Process_eSeverity_Level severity_level; /**< The severity Level (Level 1 - 5) */ + eCAL::Process::eSeverity severity; /**< The severity (Unknown, Healthy, Warning, Critical, Failed) */ + eCAL::Process::eSeverityLevel severity_level; /**< The severity Level (Level 1 - 5) */ std::string info; /**< A human readable status message */ /** * @brief Creates a new State (Unknown Level1) without info message. */ TaskState() - : severity(eCAL_Process_eSeverity::proc_sev_unknown) - , severity_level(eCAL_Process_eSeverity_Level::proc_sev_level1) + : severity(eCAL::Process::eSeverity::unknown) + , severity_level(eCAL::Process::eSeverityLevel::level1) , info("") {} @@ -46,7 +46,7 @@ class TaskState * @param severity The severity of the new state * @param severity_level The severity level of the new state */ - TaskState(eCAL_Process_eSeverity severity, eCAL_Process_eSeverity_Level severity_level) + TaskState(eCAL::Process::eSeverity severity, eCAL::Process::eSeverityLevel severity_level) : severity(severity) , severity_level(severity_level) , info("") @@ -94,53 +94,53 @@ class TaskState if (severity_string_lower == "unknown") { - severity = eCAL_Process_eSeverity::proc_sev_unknown; + severity = eCAL::Process::eSeverity::unknown; } else if (severity_string_lower == "healthy") { - severity = eCAL_Process_eSeverity::proc_sev_healthy; + severity = eCAL::Process::eSeverity::healthy; } else if (severity_string_lower == "warning") { - severity = eCAL_Process_eSeverity::proc_sev_warning; + severity = eCAL::Process::eSeverity::warning; } else if (severity_string_lower == "critical") { - severity = eCAL_Process_eSeverity::proc_sev_critical; + severity = eCAL::Process::eSeverity::critical; } else if (severity_string_lower == "failed") { - severity = eCAL_Process_eSeverity::proc_sev_failed; + severity = eCAL::Process::eSeverity::failed; } else { - severity = eCAL_Process_eSeverity::proc_sev_unknown; + severity = eCAL::Process::eSeverity::unknown; failure = true; } if (severity_level_string_lower == "level1" || severity_level_string_lower == "level 1") { - severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + severity_level = eCAL::Process::eSeverityLevel::level1; } else if (severity_level_string_lower == "level2" || severity_level_string_lower == "level 2") { - severity_level = eCAL_Process_eSeverity_Level::proc_sev_level2; + severity_level = eCAL::Process::eSeverityLevel::level2; } else if (severity_level_string_lower == "level3" || severity_level_string_lower == "level 3") { - severity_level = eCAL_Process_eSeverity_Level::proc_sev_level3; + severity_level = eCAL::Process::eSeverityLevel::level3; } else if (severity_level_string_lower == "level4" || severity_level_string_lower == "level 4") { - severity_level = eCAL_Process_eSeverity_Level::proc_sev_level4; + severity_level = eCAL::Process::eSeverityLevel::level4; } else if (severity_level_string_lower == "level5" || severity_level_string_lower == "level 5") { - severity_level = eCAL_Process_eSeverity_Level::proc_sev_level5; + severity_level = eCAL::Process::eSeverityLevel::level5; } else { - severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + severity_level = eCAL::Process::eSeverityLevel::level1; failure = true; } @@ -157,19 +157,19 @@ class TaskState { switch (severity_level) { - case eCAL_Process_eSeverity_Level::proc_sev_level1: + case eCAL::Process::eSeverityLevel::level1: severity_level_string = "Level1"; break; - case eCAL_Process_eSeverity_Level::proc_sev_level2: + case eCAL::Process::eSeverityLevel::level2: severity_level_string = "Level2"; break; - case eCAL_Process_eSeverity_Level::proc_sev_level3: + case eCAL::Process::eSeverityLevel::level3: severity_level_string = "Level3"; break; - case eCAL_Process_eSeverity_Level::proc_sev_level4: + case eCAL::Process::eSeverityLevel::level4: severity_level_string = "Level4"; break; - case eCAL_Process_eSeverity_Level::proc_sev_level5: + case eCAL::Process::eSeverityLevel::level5: severity_level_string = "Level5"; break; default: @@ -178,19 +178,19 @@ class TaskState switch (severity) { - case eCAL_Process_eSeverity::proc_sev_unknown: + case eCAL::Process::eSeverity::unknown: severity_string = "Unknown"; break; - case eCAL_Process_eSeverity::proc_sev_healthy: + case eCAL::Process::eSeverity::healthy: severity_string = "Healthy"; break; - case eCAL_Process_eSeverity::proc_sev_warning: + case eCAL::Process::eSeverity::warning: severity_string = "Warning"; break; - case eCAL_Process_eSeverity::proc_sev_critical: + case eCAL::Process::eSeverity::critical: severity_string = "Critical"; break; - case eCAL_Process_eSeverity::proc_sev_failed: + case eCAL::Process::eSeverity::failed: severity_string = "Failed"; break; default: @@ -215,17 +215,17 @@ class TaskState void FromInt(int combined_severity) { // We want to directly cast the severities. That will lead to funny bugs if someone eventually decides to change the ranges. - static_assert((int)eCAL_Process_eSeverity::proc_sev_unknown == 0, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); - static_assert((int)eCAL_Process_eSeverity::proc_sev_failed == 4, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); - static_assert((int)eCAL_Process_eSeverity_Level::proc_sev_level1 == 1, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); - static_assert((int)eCAL_Process_eSeverity_Level::proc_sev_level5 == 5, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverity::unknown == 0, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverity::failed == 4, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverityLevel::level1 == 1, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverityLevel::level5 == 5, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); // limit the interger to the desired range combined_severity = std::max(std::min(combined_severity, 24), 0); // calculate the interger severity / -level - severity = (eCAL_Process_eSeverity) (combined_severity / 5); - severity_level = (eCAL_Process_eSeverity_Level)(combined_severity % 5 + 1); + severity = (eCAL::Process::eSeverity) (combined_severity / 5); + severity_level = (eCAL::Process::eSeverityLevel)(combined_severity % 5 + 1); } /** @@ -245,10 +245,10 @@ class TaskState int ToInt() const { // We want to directly cast the severities. That will lead to funny bugs if someone eventually decides to change the ranges. - static_assert((int)eCAL_Process_eSeverity::proc_sev_unknown == 0, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); - static_assert((int)eCAL_Process_eSeverity::proc_sev_failed == 4, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); - static_assert((int)eCAL_Process_eSeverity_Level::proc_sev_level1 == 1, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); - static_assert((int)eCAL_Process_eSeverity_Level::proc_sev_level5 == 5, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverity::unknown == 0, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverity::failed == 4, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverityLevel::level1 == 1, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); + static_assert((int)eCAL::Process::eSeverityLevel::level5 == 5, "Somebody shifted the severity values! We expect severities to have a rage 0-4 and severity levels to have a range of 1-5!"); return ((int)severity * 5) + ((int)severity_level - 1); } diff --git a/app/sys/sys_core/src/config/config_manager.cpp b/app/sys/sys_core/src/config/config_manager.cpp index 2e99b7c2fb..da2515ef9a 100644 --- a/app/sys/sys_core/src/config/config_manager.cpp +++ b/app/sys/sys_core/src/config/config_manager.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -101,15 +101,15 @@ bool ConfigManager::LoadConfig(EcalSys& ecalsys, const std::string& path, bool a restart_at_severity.FromInt(restart_below_severity.ToInt() + 1); // parse the start visibility - eCAL_Process_eStartMode visibility = eCAL_Process_eStartMode::proc_smode_normal; + eCAL::Process::eStartMode visibility = eCAL::Process::eStartMode::normal; if (EcalUtils::String::Icompare(task_config.start_stop_.visibility_, "Normal") == true) - visibility = proc_smode_normal; + visibility = eCAL::Process::eStartMode::normal; if (EcalUtils::String::Icompare(task_config.start_stop_.visibility_, "Hidden") == true) - visibility = proc_smode_hidden; + visibility = eCAL::Process::eStartMode::hidden; if (EcalUtils::String::Icompare(task_config.start_stop_.visibility_, "Minimized") == true) - visibility = proc_smode_minimized; + visibility = eCAL::Process::eStartMode::minimized; if (EcalUtils::String::Icompare(task_config.start_stop_.visibility_, "Maximized") == true) - visibility = proc_smode_maximized; + visibility = eCAL::Process::eStartMode::maximized; // Find the correct runner (if the runner was the EXE / BAT runner that we removed earlier we will get a nullpointer, which is exactly what we want, here) std::shared_ptr runner(nullptr); @@ -339,16 +339,16 @@ bool ConfigManager::SaveConfig(EcalSys& ecalsys, const std::string& path, Config std::string visibility_string; switch (task->GetVisibility()) { - case proc_smode_normal: + case eCAL::Process::eStartMode::normal: visibility_string = "normal"; break; - case proc_smode_hidden: + case eCAL::Process::eStartMode::hidden: visibility_string = "hidden"; break; - case proc_smode_minimized: + case eCAL::Process::eStartMode::minimized: visibility_string = "minimized"; break; - case proc_smode_maximized: + case eCAL::Process::eStartMode::maximized: visibility_string = "maximized"; break; default: diff --git a/app/sys/sys_core/src/connection/connection_manager.cpp b/app/sys/sys_core/src/connection/connection_manager.cpp index e048f9130d..a492743c48 100644 --- a/app/sys/sys_core/src/connection/connection_manager.cpp +++ b/app/sys/sys_core/src/connection/connection_manager.cpp @@ -1,6 +1,6 @@ #include "connection_manager.h" -#include +#include namespace eCAL { diff --git a/app/sys/sys_core/src/connection/local_connection.cpp b/app/sys/sys_core/src/connection/local_connection.cpp index 27d7829b23..ca9c22f74b 100644 --- a/app/sys/sys_core/src/connection/local_connection.cpp +++ b/app/sys/sys_core/src/connection/local_connection.cpp @@ -2,7 +2,7 @@ #include -#include +#include namespace eCAL { diff --git a/app/sys/sys_core/src/connection/remote_connection.cpp b/app/sys/sys_core/src/connection/remote_connection.cpp index e2b03694cc..4330ddeaf4 100644 --- a/app/sys/sys_core/src/connection/remote_connection.cpp +++ b/app/sys/sys_core/src/connection/remote_connection.cpp @@ -3,6 +3,9 @@ #include #include +#include + +#include namespace eCAL { @@ -124,9 +127,27 @@ namespace eCAL { std::lock_guard connection_lock(connection_mutex_); - eCAL::ServiceResponseVecT service_response_vec; + eCAL::v5::ServiceResponseVecT service_response_vec; constexpr int timeout_ms = 1000; + // After client creation it takes some time for the client to be actually connected. + // As the call and the creation is too close together, the first call will fail. + // Here we wait until the connection is established. + // + // The overall handling will be reworked when using the V6 implementation. + // + if (!sys_client_service_.IsConnected()) + { + const auto maximum_wait_time = std::chrono::milliseconds(2 * eCAL::GetConfiguration().registration.registration_refresh); + const std::chrono::milliseconds wait_time(50); + + const auto start_time = std::chrono::steady_clock::now(); + while (std::chrono::steady_clock::now() - start_time <= maximum_wait_time && !sys_client_service_.IsConnected()) + { + std::this_thread::sleep_for(wait_time); + } + } + if (sys_client_service_.Call(method_name, request.SerializeAsString(), timeout_ms, &service_response_vec)) { if (service_response_vec.size() > 0) diff --git a/app/sys/sys_core/src/ecal_sys_monitor.cpp b/app/sys/sys_core/src/ecal_sys_monitor.cpp index 6455eb9aa4..142093336c 100644 --- a/app/sys/sys_core/src/ecal_sys_monitor.cpp +++ b/app/sys/sys_core/src/ecal_sys_monitor.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -133,8 +133,8 @@ void EcalSysMonitor::UpdateTaskStates(const std::list lock(m_monitoring_mutex); TaskState task_state; - task_state.severity = eCAL_Process_eSeverity::proc_sev_unknown; - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + task_state.severity = eCAL::Process::eSeverity::unknown; + task_state.severity_level = eCAL::Process::eSeverityLevel::level1; bool task_mapping_found = false; if (!(task->IsMonitoringEnabled())) @@ -176,8 +176,8 @@ void EcalSysMonitor::UpdateTaskStates(const std::listIsMonitoringEnabled() && task->FoundInMonitorOnce() && !is_starting_or_stopping) { task_state.info = "Externally closed"; - task_state.severity = eCAL_Process_eSeverity::proc_sev_failed; - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level5; + task_state.severity = eCAL::Process::eSeverity::failed; + task_state.severity_level = eCAL::Process::eSeverityLevel::level5; } else { @@ -187,8 +187,8 @@ void EcalSysMonitor::UpdateTaskStates(const std::listGetMonitoringTaskState(); TaskState restart_state = task->GetRestartAtSeverity(); - if (current_state.severity != eCAL_Process_eSeverity::proc_sev_unknown + if (current_state.severity != eCAL::Process::eSeverity::unknown && current_state >= restart_state) { if (!is_starting_or_stopping) diff --git a/app/sys/sys_core/src/proto_helpers.cpp b/app/sys/sys_core/src/proto_helpers.cpp index a22cfc937a..dabd6db574 100644 --- a/app/sys/sys_core/src/proto_helpers.cpp +++ b/app/sys/sys_core/src/proto_helpers.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,44 +36,44 @@ namespace eCAL switch (task_state_pb.severity()) { case eCAL::pb::sys::eProcessSeverity::proc_sev_unknown: - task_state.severity = eCAL_Process_eSeverity::proc_sev_unknown; + task_state.severity = eCAL::Process::eSeverity::unknown; break; case eCAL::pb::sys::eProcessSeverity::proc_sev_healthy: - task_state.severity = eCAL_Process_eSeverity::proc_sev_healthy; + task_state.severity = eCAL::Process::eSeverity::healthy; break; case eCAL::pb::sys::eProcessSeverity::proc_sev_warning: - task_state.severity = eCAL_Process_eSeverity::proc_sev_warning; + task_state.severity = eCAL::Process::eSeverity::warning; break; case eCAL::pb::sys::eProcessSeverity::proc_sev_critical: - task_state.severity = eCAL_Process_eSeverity::proc_sev_critical; + task_state.severity = eCAL::Process::eSeverity::critical; break; case eCAL::pb::sys::eProcessSeverity::proc_sev_failed: - task_state.severity = eCAL_Process_eSeverity::proc_sev_failed; + task_state.severity = eCAL::Process::eSeverity::failed; break; default: - task_state.severity = eCAL_Process_eSeverity::proc_sev_unknown; + task_state.severity = eCAL::Process::eSeverity::unknown; break; } switch (task_state_pb.severity_level()) { case eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level1: - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + task_state.severity_level = eCAL::Process::eSeverityLevel::level1; break; case eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level2: - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level2; + task_state.severity_level = eCAL::Process::eSeverityLevel::level2; break; case eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level3: - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level3; + task_state.severity_level = eCAL::Process::eSeverityLevel::level3; break; case eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level4: - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level4; + task_state.severity_level = eCAL::Process::eSeverityLevel::level4; break; case eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level5: - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level5; + task_state.severity_level = eCAL::Process::eSeverityLevel::level5; break; default: - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + task_state.severity_level = eCAL::Process::eSeverityLevel::level1; break; } @@ -102,7 +102,7 @@ namespace eCAL task->SetMonitoringTaskState(FromProtobuf(task_pb.state())); auto restart_at_severity = FromProtobuf(task_pb.restart_by_severity()); - if (restart_at_severity.severity != eCAL_Process_eSeverity::proc_sev_unknown) + if (restart_at_severity.severity != eCAL::Process::eSeverity::unknown) { task->SetRestartBySeverityEnabled(true); task->SetRestartAtSeverity(restart_at_severity); @@ -186,19 +186,19 @@ namespace eCAL { switch (task_state.severity) { - case eCAL_Process_eSeverity::proc_sev_unknown: + case eCAL::Process::eSeverity::unknown: task_state_pb.set_severity(eCAL::pb::sys::eProcessSeverity::proc_sev_unknown); break; - case eCAL_Process_eSeverity::proc_sev_healthy: + case eCAL::Process::eSeverity::healthy: task_state_pb.set_severity(eCAL::pb::sys::eProcessSeverity::proc_sev_healthy); break; - case eCAL_Process_eSeverity::proc_sev_warning: + case eCAL::Process::eSeverity::warning: task_state_pb.set_severity(eCAL::pb::sys::eProcessSeverity::proc_sev_warning); break; - case eCAL_Process_eSeverity::proc_sev_critical: + case eCAL::Process::eSeverity::critical: task_state_pb.set_severity(eCAL::pb::sys::eProcessSeverity::proc_sev_critical); break; - case eCAL_Process_eSeverity::proc_sev_failed: + case eCAL::Process::eSeverity::failed: task_state_pb.set_severity(eCAL::pb::sys::eProcessSeverity::proc_sev_failed); break; default: @@ -208,19 +208,19 @@ namespace eCAL switch (task_state.severity_level) { - case eCAL_Process_eSeverity_Level::proc_sev_level1: + case eCAL::Process::eSeverityLevel::level1: task_state_pb.set_severity_level(eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level1); break; - case eCAL_Process_eSeverity_Level::proc_sev_level2: + case eCAL::Process::eSeverityLevel::level2: task_state_pb.set_severity_level(eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level2); break; - case eCAL_Process_eSeverity_Level::proc_sev_level3: + case eCAL::Process::eSeverityLevel::level3: task_state_pb.set_severity_level(eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level3); break; - case eCAL_Process_eSeverity_Level::proc_sev_level4: + case eCAL::Process::eSeverityLevel::level4: task_state_pb.set_severity_level(eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level4); break; - case eCAL_Process_eSeverity_Level::proc_sev_level5: + case eCAL::Process::eSeverityLevel::level5: task_state_pb.set_severity_level(eCAL::pb::sys::eProcessSeverityLevel::proc_sev_level5); break; default: diff --git a/app/sys/sys_core/src/task/ecal_sys_task.cpp b/app/sys/sys_core/src/task/ecal_sys_task.cpp index fcc4f1a969..997dff384d 100644 --- a/app/sys/sys_core/src/task/ecal_sys_task.cpp +++ b/app/sys/sys_core/src/task/ecal_sys_task.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,7 @@ EcalSysTask::EcalSysTask() , m_working_directory ("") , m_launch_order (0) , m_timeout_after_start (std::chrono::nanoseconds(0)) - , m_visibility (eCAL_Process_eStartMode::proc_smode_normal) + , m_visibility (eCAL::Process::eStartMode::normal) , m_monitoring_enabled (true) , m_restart_by_severity_enabled(false) @@ -105,7 +105,7 @@ std::chrono::nanoseconds EcalSysTask::GetTimeoutAfterStart() return m_timeout_after_start; } -eCAL_Process_eStartMode EcalSysTask::GetVisibility() +eCAL::Process::eStartMode EcalSysTask::GetVisibility() { std::lock_guard task_lock(mutex); return m_visibility; @@ -190,7 +190,7 @@ void EcalSysTask::SetTimeoutAfterStart(std::chrono::nanoseconds timeout) m_config_modified_since_start = true; } -void EcalSysTask::SetVisibility(eCAL_Process_eStartMode visibility) +void EcalSysTask::SetVisibility(eCAL::Process::eStartMode visibility) { std::lock_guard task_lock(mutex); m_visibility = visibility; diff --git a/app/sys/sys_core/src/task/task_group.cpp b/app/sys/sys_core/src/task/task_group.cpp index b9e5e5f7f8..9c994f107a 100644 --- a/app/sys/sys_core/src/task/task_group.cpp +++ b/app/sys/sys_core/src/task/task_group.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,7 +114,7 @@ bool TaskGroup::GroupState::Evaluate() { // If current state is worse than the minimal state TaskState current_state = minimal_state.first->GetMonitoringTaskState(); - if (current_state.severity == eCAL_Process_eSeverity::proc_sev_unknown || current_state > minimal_state.second) + if (current_state.severity == eCAL::Process::eSeverity::unknown || current_state > minimal_state.second) { return false; } diff --git a/app/sys/sys_core/src/taskaction_threads/start_task_list_thread.cpp b/app/sys/sys_core/src/taskaction_threads/start_task_list_thread.cpp index b2af65d3bc..d3f969a499 100644 --- a/app/sys/sys_core/src/taskaction_threads/start_task_list_thread.cpp +++ b/app/sys/sys_core/src/taskaction_threads/start_task_list_thread.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -71,8 +71,8 @@ void StartTaskListThread::Run() TaskState task_state; task_state.info = ""; - task_state.severity = eCAL_Process_eSeverity::proc_sev_unknown; - task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + task_state.severity = eCAL::Process::eSeverity::unknown; + task_state.severity_level = eCAL::Process::eSeverityLevel::level1; task->SetMonitoringTaskState(task_state); task->ResetConfigModifiedSinceStart(); diff --git a/app/sys/sys_gui/CMakeLists.txt b/app/sys/sys_gui/CMakeLists.txt index 85244107f6..a893413b1b 100644 --- a/app/sys/sys_gui/CMakeLists.txt +++ b/app/sys/sys_gui/CMakeLists.txt @@ -174,7 +174,7 @@ ecal_add_app_qt(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets CustomQt diff --git a/app/sys/sys_gui/src/main.cpp b/app/sys/sys_gui/src/main.cpp index 6327d8884c..88f1415137 100644 --- a/app/sys/sys_gui/src/main.cpp +++ b/app/sys/sys_gui/src/main.cpp @@ -144,7 +144,7 @@ int main(int argc, char *argv[]) ////////////////////////////////////////////////////////////////////////////// // Just make sure that eCAL is initialized - eCAL::Initialize(argc, argv, "eCALSysGUI", eCAL::Init::All); + eCAL::Initialize("eCALSysGUI", eCAL::Init::All); ////////////////////////////////////// // --config diff --git a/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.cpp b/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.cpp index bc77b7faec..0651dfb7c4 100644 --- a/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.cpp +++ b/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.cpp @@ -19,9 +19,11 @@ #include "about_dialog.h" #include "ecalsys/esys_defs.h" -#include + +#include #include +#include AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) @@ -29,8 +31,13 @@ AboutDialog::AboutDialog(QWidget *parent) ui_.setupUi(this); ui_.version_label->setText("Version: " + QString(ECAL_SYS_VERSION_STRING)); ui_.ecalversion_label->setText("eCAL " + QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); - connect(ui_.button_box->button(QDialogButtonBox::StandardButton::Ok), SIGNAL(clicked()), this, SLOT(close())); -} + + ui_.ecal_runtime_version_string_label->setText(QString::fromStdString(eCAL::GetVersionString()) + " (" + QString::fromStdString(eCAL::GetVersionDateString()) + ")"); + ui_.ecal_compiletime_versin_string_label->setText(QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + ui_.qt_runtime_version_string_label->setText(QString(qVersion())); + ui_.qt_compiletime_version_string_label->setText(QString(QT_VERSION_STR)); + + connect(ui_.button_box->button(QDialogButtonBox::StandardButton::Ok), SIGNAL(clicked()), this, SLOT(close()));} AboutDialog::~AboutDialog() { diff --git a/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.ui b/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.ui index 41bbfbd8d2..d6cda09428 100644 --- a/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.ui +++ b/app/sys/sys_gui/src/widgets/about_dialog/about_dialog.ui @@ -7,7 +7,7 @@ 0 0 326 - 209 + 228 @@ -62,7 +62,6 @@ Advanced Engineering Department Developed by Florian Reimold Based on work by Ileana Zepa, Narcisa Mironese, Andrei Toader - @@ -73,6 +72,68 @@ Based on work by Ileana Zepa, Narcisa Mironese, Andrei Toader + + + + + + + Qt runtime version: + + + + + + + qt-runtime-version + + + + + + + eCAL runtime version: + + + + + + + ecal-runtime-version + + + + + + + eCAL compile-time version: + + + + + + + ecal-compiletime-version + + + + + + + Qt compile-time version: + + + + + + + qt-compiletime-version + + + + + + diff --git a/app/sys/sys_gui/src/widgets/group_edit_widget/group_edit_widget.cpp b/app/sys/sys_gui/src/widgets/group_edit_widget/group_edit_widget.cpp index 5a6741d64e..63a8bf4aaf 100644 --- a/app/sys/sys_gui/src/widgets/group_edit_widget/group_edit_widget.cpp +++ b/app/sys/sys_gui/src/widgets/group_edit_widget/group_edit_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -642,8 +642,8 @@ void GroupEditWidget::stateAddTaskButtonClicked() { TaskTreeItem* task_tree_item = static_cast(tree_item); TaskState minimal_task_state; - minimal_task_state.severity = eCAL_Process_eSeverity::proc_sev_healthy; - minimal_task_state.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + minimal_task_state.severity = eCAL::Process::eSeverity::healthy; + minimal_task_state.severity_level = eCAL::Process::eSeverityLevel::level1; std::pair, TaskState> min_state(task_tree_item->getTask(), minimal_task_state); auto minimal_states_list = group_state_->GetMinimalStatesList(); diff --git a/app/sys/sys_gui/src/widgets/group_edit_widget/severity_picker_delegate.cpp b/app/sys/sys_gui/src/widgets/group_edit_widget/severity_picker_delegate.cpp index 369ad2108b..db1ff2c4eb 100644 --- a/app/sys/sys_gui/src/widgets/group_edit_widget/severity_picker_delegate.cpp +++ b/app/sys/sys_gui/src/widgets/group_edit_widget/severity_picker_delegate.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,13 +65,13 @@ void SeverityPickerDelegate::setEditorData(QWidget *editor, const QModelIndex &i if (index.column() == (int)GroupStateMinTaskStateTreeModel::Columns::SEVERITY) { - eCAL_Process_eSeverity severity = (eCAL_Process_eSeverity)(current_int); + eCAL::Process::eSeverity severity = (eCAL::Process::eSeverity)(current_int); SeverityModel* severity_model = static_cast(combobox->model()); combobox->setCurrentIndex(severity_model->getRow(severity)); } else if (index.column() == (int)GroupStateMinTaskStateTreeModel::Columns::SEVERITY_LEVEL) { - eCAL_Process_eSeverity_Level severity_level = (eCAL_Process_eSeverity_Level)(current_int); + eCAL::Process::eSeverityLevel severity_level = (eCAL::Process::eSeverityLevel)(current_int); SeverityLevelModel* severity_level_model = static_cast(combobox->model()); combobox->setCurrentIndex(severity_level_model->getRow(severity_level)); } @@ -86,13 +86,13 @@ void SeverityPickerDelegate::setModelData(QWidget *editor, QAbstractItemModel *m if (index.column() == (int)GroupStateMinTaskStateTreeModel::Columns::SEVERITY) { SeverityModel* severity_model = static_cast(combobox->model()); - eCAL_Process_eSeverity severity = severity_model->getSeverity(combobox->currentIndex()); + eCAL::Process::eSeverity severity = severity_model->getSeverity(combobox->currentIndex()); model->setData(index, (int)severity, Qt::EditRole); } else if (index.column() == (int)GroupStateMinTaskStateTreeModel::Columns::SEVERITY_LEVEL) { SeverityLevelModel* severity_level_model = static_cast(combobox->model()); - eCAL_Process_eSeverity_Level severity_level = severity_level_model->getSeverityLevel(combobox->currentIndex()); + eCAL::Process::eSeverityLevel severity_level = severity_level_model->getSeverityLevel(combobox->currentIndex()); model->setData(index, (int)severity_level, Qt::EditRole); } } diff --git a/app/sys/sys_gui/src/widgets/import_from_cloud_widget/import_from_cloud_widget.cpp b/app/sys/sys_gui/src/widgets/import_from_cloud_widget/import_from_cloud_widget.cpp index e2882fd2c3..3a3b5bc6de 100644 --- a/app/sys/sys_gui/src/widgets/import_from_cloud_widget/import_from_cloud_widget.cpp +++ b/app/sys/sys_gui/src/widgets/import_from_cloud_widget/import_from_cloud_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -224,8 +224,8 @@ void ImportFromCloudWidget::reload() for (auto& task : task_list_) { TaskState restart_at_severity; - restart_at_severity.severity = eCAL_Process_eSeverity::proc_sev_failed; - restart_at_severity.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + restart_at_severity.severity = eCAL::Process::eSeverity::failed; + restart_at_severity.severity_level = eCAL::Process::eSeverityLevel::level1; task->SetRestartAtSeverity(restart_at_severity); } @@ -923,7 +923,7 @@ void ImportFromCloudWidget::import() void ImportFromCloudWidget::loadExcludeTasksFilter() { - std::string default_cfg_file_path = eCAL::Util::GeteCALActiveIniFile(); + const std::string default_cfg_file_path = eCAL::GetConfiguration().GetConfigurationFilePath(); QFile default_cfg_file(default_cfg_file_path.c_str()); if (default_cfg_file.exists()) { diff --git a/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.cpp b/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.cpp index 166ff408c7..f4d1628e79 100644 --- a/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.cpp +++ b/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.cpp @@ -73,7 +73,7 @@ MmaHostItem::MmaHostItem(QTreeWidget* tree_widget, const QString& hostname) // Create eCAL Subscriber mma_subscriber = std::unique_ptr> (new eCAL::protobuf::CSubscriber("machine_state_" + hostname_.toStdString())); - mma_subscriber->AddReceiveCallback(std::bind(&MmaHostItem::mmaReceivedCallback, this, std::placeholders::_1, std::placeholders::_2)); + mma_subscriber->SetReceiveCallback(std::bind(&MmaHostItem::mmaReceivedCallback, this, std::placeholders::_1, std::placeholders::_2)); // Register custom Type in order to directly pass the monitoring state qRegisterMetaType("eCAL::pb::mma::State"); @@ -227,10 +227,10 @@ void MmaHostItem::disable() setEnabled(false); } -void MmaHostItem::mmaReceivedCallback(const char* /*topic_name*/, const eCAL::pb::mma::State& state) +void MmaHostItem::mmaReceivedCallback(const eCAL::STopicId& /*topic_id_*/, const eCAL::pb::mma::State& state_) { // only emit the signal in order to make use of the Qt event loop - emit mmaReceivedSignal(state); + emit mmaReceivedSignal(state_); } void MmaHostItem::machineStateChanged(eCAL::pb::mma::State state) diff --git a/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.h b/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.h index d33ba9ff5c..e912deb8d5 100644 --- a/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.h +++ b/app/sys/sys_gui/src/widgets/mmawidget/mma_host_item.h @@ -85,7 +85,7 @@ public slots: QTimer* deactivation_timer; - void mmaReceivedCallback(const char* topic_name, const eCAL::pb::mma::State& state); + void mmaReceivedCallback(const eCAL::STopicId& topic_id_, const eCAL::pb::mma::State& state_); QString normalizedDataAsString(unsigned long long bytes); diff --git a/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.cpp b/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.cpp index 4f321e1610..846c41f1d4 100644 --- a/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.cpp +++ b/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,11 +22,11 @@ SeverityLevelModel::SeverityLevelModel(QObject *parent) : QAbstractListModel(parent) { - rows.push_back(std::make_pair(QString("Level 1"), eCAL_Process_eSeverity_Level::proc_sev_level1)); - rows.push_back(std::make_pair(QString("Level 2"), eCAL_Process_eSeverity_Level::proc_sev_level2)); - rows.push_back(std::make_pair(QString("Level 3"), eCAL_Process_eSeverity_Level::proc_sev_level3)); - rows.push_back(std::make_pair(QString("Level 4"), eCAL_Process_eSeverity_Level::proc_sev_level4)); - rows.push_back(std::make_pair(QString("Level 5"), eCAL_Process_eSeverity_Level::proc_sev_level5)); + rows.push_back(std::make_pair(QString("Level 1"), eCAL::Process::eSeverityLevel::level1)); + rows.push_back(std::make_pair(QString("Level 2"), eCAL::Process::eSeverityLevel::level2)); + rows.push_back(std::make_pair(QString("Level 3"), eCAL::Process::eSeverityLevel::level3)); + rows.push_back(std::make_pair(QString("Level 4"), eCAL::Process::eSeverityLevel::level4)); + rows.push_back(std::make_pair(QString("Level 5"), eCAL::Process::eSeverityLevel::level5)); } SeverityLevelModel::~SeverityLevelModel() @@ -51,12 +51,12 @@ QString SeverityLevelModel::getString(int row) const return rows[row].first; } -eCAL_Process_eSeverity_Level SeverityLevelModel::getSeverityLevel(int row) const +eCAL::Process::eSeverityLevel SeverityLevelModel::getSeverityLevel(int row) const { return rows[row].second; } -int SeverityLevelModel::getRow(eCAL_Process_eSeverity_Level level) const +int SeverityLevelModel::getRow(eCAL::Process::eSeverityLevel level) const { for (int i = 0; i < (int)rows.size(); i++) { diff --git a/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.h b/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.h index 5919b0f547..a761d6d464 100644 --- a/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.h +++ b/app/sys/sys_gui/src/widgets/severity_model/severity_level_model.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,10 +37,10 @@ class SeverityLevelModel : public QAbstractListModel QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QString getString(int row) const; - eCAL_Process_eSeverity_Level getSeverityLevel(int row) const; + eCAL::Process::eSeverityLevel getSeverityLevel(int row) const; - int getRow(eCAL_Process_eSeverity_Level level) const; + int getRow(eCAL::Process::eSeverityLevel level) const; private: - std::vector> rows; + std::vector> rows; }; \ No newline at end of file diff --git a/app/sys/sys_gui/src/widgets/severity_model/severity_model.cpp b/app/sys/sys_gui/src/widgets/severity_model/severity_model.cpp index 6073bd152d..2814adbd02 100644 --- a/app/sys/sys_gui/src/widgets/severity_model/severity_model.cpp +++ b/app/sys/sys_gui/src/widgets/severity_model/severity_model.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,12 @@ SeverityModel::SeverityModel(QObject *parent, bool include_unknown_severity) { if (include_unknown_severity) { - rows.push_back(std::make_pair(QString("Unknown"), eCAL_Process_eSeverity::proc_sev_unknown)); + rows.push_back(std::make_pair(QString("Unknown"), eCAL::Process::eSeverity::unknown)); } - rows.push_back(std::make_pair(QString("Healthy"), eCAL_Process_eSeverity::proc_sev_healthy)); - rows.push_back(std::make_pair(QString("Warning"), eCAL_Process_eSeverity::proc_sev_warning)); - rows.push_back(std::make_pair(QString("Critical"), eCAL_Process_eSeverity::proc_sev_critical)); - rows.push_back(std::make_pair(QString("Failed"), eCAL_Process_eSeverity::proc_sev_failed)); + rows.push_back(std::make_pair(QString("Healthy"), eCAL::Process::eSeverity::healthy)); + rows.push_back(std::make_pair(QString("Warning"), eCAL::Process::eSeverity::warning)); + rows.push_back(std::make_pair(QString("Critical"), eCAL::Process::eSeverity::critical)); + rows.push_back(std::make_pair(QString("Failed"), eCAL::Process::eSeverity::failed)); } SeverityModel::~SeverityModel() @@ -54,12 +54,12 @@ QString SeverityModel::getString(int row) const return rows[row].first; } -eCAL_Process_eSeverity SeverityModel::getSeverity(int row) const +eCAL::Process::eSeverity SeverityModel::getSeverity(int row) const { return rows[row].second; } -int SeverityModel::getRow(eCAL_Process_eSeverity severity) const +int SeverityModel::getRow(eCAL::Process::eSeverity severity) const { for (int i = 0; i < (int)rows.size(); i++) { diff --git a/app/sys/sys_gui/src/widgets/severity_model/severity_model.h b/app/sys/sys_gui/src/widgets/severity_model/severity_model.h index 4fce77a5a0..26f3a4efde 100644 --- a/app/sys/sys_gui/src/widgets/severity_model/severity_model.h +++ b/app/sys/sys_gui/src/widgets/severity_model/severity_model.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,10 +37,10 @@ class SeverityModel : public QAbstractListModel QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QString getString(int row) const; - eCAL_Process_eSeverity getSeverity(int row) const; + eCAL::Process::eSeverity getSeverity(int row) const; - int getRow(eCAL_Process_eSeverity severity) const; + int getRow(eCAL::Process::eSeverity severity) const; private: - std::vector> rows; + std::vector> rows; }; \ No newline at end of file diff --git a/app/sys/sys_gui/src/widgets/taskwidget/task_widget.cpp b/app/sys/sys_gui/src/widgets/taskwidget/task_widget.cpp index fbc4ed96fa..db9fbdad14 100644 --- a/app/sys/sys_gui/src/widgets/taskwidget/task_widget.cpp +++ b/app/sys/sys_gui/src/widgets/taskwidget/task_widget.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -269,14 +269,14 @@ void TaskWidget::autoSizeColumns() std::shared_ptr example_runner(new EcalSysRunner()); example_runner->SetName ("RunTask (new)___"); example_task->SetRunner (example_runner); - example_task->SetVisibility (eCAL_Process_eStartMode::proc_smode_maximized); + example_task->SetVisibility (eCAL::Process::eStartMode::maximized); example_task->SetTimeoutAfterStart (std::chrono::milliseconds(99999)); example_task->SetMonitoringEnabled (false); example_task->SetRestartBySeverityEnabled (false); - example_task->SetRestartAtSeverity (TaskState(eCAL_Process_eSeverity::proc_sev_warning, eCAL_Process_eSeverity_Level::proc_sev_level5)); + example_task->SetRestartAtSeverity (TaskState(eCAL::Process::eSeverity::warning, eCAL::Process::eSeverityLevel::level5)); example_task->SetPids (std::vector{9999999}); example_task->SetHostStartedOn ("CARPC00___"); - example_task->SetMonitoringTaskState (TaskState(eCAL_Process_eSeverity::proc_sev_warning, eCAL_Process_eSeverity_Level::proc_sev_level5)); + example_task->SetMonitoringTaskState (TaskState(eCAL::Process::eSeverity::warning, eCAL::Process::eSeverityLevel::level5)); // We don't want to resize all Columns, as e.g. for the Algo Path we really can't know how much text will be in there. static const std::vector columns_to_resize = @@ -747,8 +747,8 @@ void TaskWidget::addTask() new_task->SetTarget(eCAL::Process::GetHostName()); TaskState min_acceptable_severity; - min_acceptable_severity.severity = eCAL_Process_eSeverity::proc_sev_failed; - min_acceptable_severity.severity_level = eCAL_Process_eSeverity_Level::proc_sev_level1; + min_acceptable_severity.severity = eCAL::Process::eSeverity::failed; + min_acceptable_severity.severity_level = eCAL::Process::eSeverityLevel::level1; new_task->SetRestartAtSeverity(min_acceptable_severity); // Add Task to the actual model @@ -1399,16 +1399,16 @@ void TaskWidget::updateEditAreaVisibility(std::vectorGetVisibility()) { - case eCAL_Process_eStartMode::proc_smode_hidden: + case eCAL::Process::eStartMode::hidden: visibility_string = "Hidden"; break; - case eCAL_Process_eStartMode::proc_smode_normal: + case eCAL::Process::eStartMode::normal: visibility_string = "Normal"; break; - case eCAL_Process_eStartMode::proc_smode_minimized: + case eCAL::Process::eStartMode::minimized: visibility_string = "Minimized"; break; - case eCAL_Process_eStartMode::proc_smode_maximized: + case eCAL::Process::eStartMode::maximized: visibility_string = "Maximized"; break; default: @@ -1531,7 +1531,7 @@ void TaskWidget::updateEditAreaRestartAtSeverity(std::vectorblockSignals(true); if (task_list.size() == 0) { - ui_.restart_by_severity_combobox->setCurrentIndex(severity_model_->getRow(eCAL_Process_eSeverity::proc_sev_failed)); + ui_.restart_by_severity_combobox->setCurrentIndex(severity_model_->getRow(eCAL::Process::eSeverity::failed)); } else { @@ -1553,7 +1553,7 @@ void TaskWidget::updateEditAreaRestartAtSeverityLevel(std::vectorblockSignals(true); if (task_list.size() == 0) { - ui_.restart_by_severity_level_combobox->setCurrentIndex(severity_level_model_->getRow(eCAL_Process_eSeverity_Level::proc_sev_level1)); + ui_.restart_by_severity_level_combobox->setCurrentIndex(severity_level_model_->getRow(eCAL::Process::eSeverityLevel::level1)); } else { @@ -2106,22 +2106,22 @@ void TaskWidget::visibilityTextChanged() if (selected_tasks.size() != 0) { std::string text = ui_.visibility_combobox->currentText().toStdString(); - eCAL_Process_eStartMode visibility = eCAL_Process_eStartMode::proc_smode_normal; + eCAL::Process::eStartMode visibility = eCAL::Process::eStartMode::normal; if (text == "Normal") { - visibility = eCAL_Process_eStartMode::proc_smode_normal; + visibility = eCAL::Process::eStartMode::normal; } else if (text == "Maximized") { - visibility = eCAL_Process_eStartMode::proc_smode_maximized; + visibility = eCAL::Process::eStartMode::maximized; } else if (text == "Minimized") { - visibility = eCAL_Process_eStartMode::proc_smode_minimized; + visibility = eCAL::Process::eStartMode::minimized; } else if (text == "Hidden") { - visibility = eCAL_Process_eStartMode::proc_smode_hidden; + visibility = eCAL::Process::eStartMode::hidden; } std::vector> modified_tasks; @@ -2276,7 +2276,7 @@ void TaskWidget::restartBySeverityIndexChanged(int index) auto selected_tasks = getSelectedTasks(); if (selected_tasks.size() != 0) { - eCAL_Process_eSeverity selected_severity = severity_model_->getSeverity(index); + eCAL::Process::eSeverity selected_severity = severity_model_->getSeverity(index); std::vector> modified_tasks; for (auto& task : selected_tasks) @@ -2302,7 +2302,7 @@ void TaskWidget::restartBySeverityLevelIndexChanged(int index) auto selected_tasks = getSelectedTasks(); if (selected_tasks.size() != 0) { - eCAL_Process_eSeverity_Level selected_severity_level = severity_level_model_->getSeverityLevel(index); + eCAL::Process::eSeverityLevel selected_severity_level = severity_level_model_->getSeverityLevel(index); std::vector> modified_tasks; for (auto& task : selected_tasks) diff --git a/app/sys/sys_gui/src/widgets/treemodels/group_state_min_task_state_tree_item.cpp b/app/sys/sys_gui/src/widgets/treemodels/group_state_min_task_state_tree_item.cpp index 50b854e781..9c3bfd8b08 100644 --- a/app/sys/sys_gui/src/widgets/treemodels/group_state_min_task_state_tree_item.cpp +++ b/app/sys/sys_gui/src/widgets/treemodels/group_state_min_task_state_tree_item.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -157,12 +157,12 @@ bool GroupStateMinTaskStateTreeItem::setData(int column, const QVariant& data, Q { if (column == (int)Columns::SEVERITY) { - min_task_state_.second.severity = (eCAL_Process_eSeverity)(data.toInt()); + min_task_state_.second.severity = (eCAL::Process::eSeverity)(data.toInt()); return true; } else if (column == (int)Columns::SEVERITY_LEVEL) { - min_task_state_.second.severity_level = (eCAL_Process_eSeverity_Level)(data.toInt()); + min_task_state_.second.severity_level = (eCAL::Process::eSeverityLevel)(data.toInt()); return true; } } diff --git a/app/sys/sys_gui/src/widgets/treemodels/task_tree_item.cpp b/app/sys/sys_gui/src/widgets/treemodels/task_tree_item.cpp index 2ee4ab6fec..c0bcf4aabd 100644 --- a/app/sys/sys_gui/src/widgets/treemodels/task_tree_item.cpp +++ b/app/sys/sys_gui/src/widgets/treemodels/task_tree_item.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2020 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,11 +89,11 @@ QVariant TaskTreeItem::data(Columns column, Qt::ItemDataRole role) const { switch (task_->GetVisibility()) { - case eCAL_Process_eStartMode::proc_smode_hidden: + case eCAL::Process::eStartMode::hidden: return "Hidden"; - case eCAL_Process_eStartMode::proc_smode_maximized: + case eCAL::Process::eStartMode::maximized: return "Maximized"; - case eCAL_Process_eStartMode::proc_smode_minimized: + case eCAL::Process::eStartMode::minimized: return "Minimized"; default: return "Normal"; @@ -121,8 +121,8 @@ QVariant TaskTreeItem::data(Columns column, Qt::ItemDataRole role) const TaskState restart_at_severity = task_->GetRestartAtSeverity(); restart_at_severity.ToString(state, level); return QString(state.c_str()) + - (restart_at_severity.severity != eCAL_Process_eSeverity::proc_sev_unknown ? - " (Lv " + QString::number(restart_at_severity.severity_level) + ")" : + (restart_at_severity.severity != eCAL::Process::eSeverity::unknown ? + " (Lv " + QString::number(static_cast(restart_at_severity.severity_level)) + ")" : ""); } else if (column == Columns::CURRENT_PID) @@ -144,8 +144,8 @@ QVariant TaskTreeItem::data(Columns column, Qt::ItemDataRole role) const std::string state, level; task_->GetMonitoringTaskState().ToString(state, level); return QString(state.c_str()) + - (task_->GetMonitoringTaskState().severity != eCAL_Process_eSeverity::proc_sev_unknown ? - " (Lv " + QString::number(task_->GetMonitoringTaskState().severity_level) + ")" : + (task_->GetMonitoringTaskState().severity != eCAL::Process::eSeverity::unknown ? + " (Lv " + QString::number(static_cast(task_->GetMonitoringTaskState().severity_level)) + ")" : ""); } else if (column == Columns::INFO) @@ -201,13 +201,13 @@ QVariant TaskTreeItem::data(Columns column, Qt::ItemDataRole role) const switch (state.severity) { - case eCAL_Process_eSeverity::proc_sev_healthy: + case eCAL::Process::eSeverity::healthy: return QColor(80, 225, 120); - case eCAL_Process_eSeverity::proc_sev_warning: + case eCAL::Process::eSeverity::warning: return QColor(240, 240, 50); - case eCAL_Process_eSeverity::proc_sev_critical: + case eCAL::Process::eSeverity::critical: return QColor(250, 130, 0); - case eCAL_Process_eSeverity::proc_sev_failed: + case eCAL::Process::eSeverity::failed: return QColor(240, 20, 20); default: return QVariant(); // Invalid QVariant diff --git a/app/sys/sys_python/src/module.cpp b/app/sys/sys_python/src/module.cpp index a4612ae75e..77c60fa770 100644 --- a/app/sys/sys_python/src/module.cpp +++ b/app/sys/sys_python/src/module.cpp @@ -28,7 +28,7 @@ #include "ecalsys/task/task_state.h" #include "ecalsys/config/config_version.h" -#include "ecal/ecal_process_mode.h" +#include "ecal/process_mode.h" namespace py = pybind11; diff --git a/app/util/config/CMakeLists.txt b/app/util/config/CMakeLists.txt index 08daa470c1..175743666e 100644 --- a/app/util/config/CMakeLists.txt +++ b/app/util/config/CMakeLists.txt @@ -30,7 +30,7 @@ target_include_directories(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:PCRE_STATIC;_UNICODE>) -target_link_libraries(${PROJECT_NAME} eCAL::core) +target_link_libraries(${PROJECT_NAME} PRIVATE eCAL::core) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) ecal_install_app(${PROJECT_NAME}) diff --git a/app/util/config/src/ecal_config.cpp b/app/util/config/src/ecal_config.cpp index a5bdc4db41..bd12ace599 100644 --- a/app/util/config/src/ecal_config.cpp +++ b/app/util/config/src/ecal_config.cpp @@ -23,10 +23,10 @@ #include -int main(int argc, char** argv) +int main() { // initialize eCAL API - eCAL::Initialize(argc, argv, "eCALConfig"); + eCAL::Initialize("eCALConfig"); // print config eCAL::Process::DumpConfig(); diff --git a/app/util/launcher/CMakeLists.txt b/app/util/launcher/CMakeLists.txt index 678eb3b34b..f54cbcd394 100644 --- a/app/util/launcher/CMakeLists.txt +++ b/app/util/launcher/CMakeLists.txt @@ -82,7 +82,7 @@ ecal_add_app_qt(${PROJECT_NAME} ${autogen_ui} ) -target_link_libraries (${PROJECT_NAME} +target_link_libraries (${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets eCAL::apps diff --git a/app/util/launcher/resources/NEURPOLI.TTF b/app/util/launcher/resources/NEURPOLI.TTF deleted file mode 100644 index 6db04ebc46..0000000000 Binary files a/app/util/launcher/resources/NEURPOLI.TTF and /dev/null differ diff --git a/app/util/launcher/resources/labels/exit.svg b/app/util/launcher/resources/labels/exit.svg new file mode 100644 index 0000000000..a5f49a7f81 --- /dev/null +++ b/app/util/launcher/resources/labels/exit.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/info.svg b/app/util/launcher/resources/labels/info.svg new file mode 100644 index 0000000000..dc18826613 --- /dev/null +++ b/app/util/launcher/resources/labels/info.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/logo.svg b/app/util/launcher/resources/labels/logo.svg new file mode 100644 index 0000000000..d0175ce8ae --- /dev/null +++ b/app/util/launcher/resources/labels/logo.svg @@ -0,0 +1,219 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/monitor.svg b/app/util/launcher/resources/labels/monitor.svg new file mode 100644 index 0000000000..6571478c09 --- /dev/null +++ b/app/util/launcher/resources/labels/monitor.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/play.svg b/app/util/launcher/resources/labels/play.svg new file mode 100644 index 0000000000..28ce0a1292 --- /dev/null +++ b/app/util/launcher/resources/labels/play.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/rec.svg b/app/util/launcher/resources/labels/rec.svg new file mode 100644 index 0000000000..1556c8945b --- /dev/null +++ b/app/util/launcher/resources/labels/rec.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/src/button_image_as_layers.svg b/app/util/launcher/resources/labels/src/button_image_as_layers.svg new file mode 100644 index 0000000000..ee4b616e82 --- /dev/null +++ b/app/util/launcher/resources/labels/src/button_image_as_layers.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/labels/src/button_text_as_layers.svg b/app/util/launcher/resources/labels/src/button_text_as_layers.svg new file mode 100644 index 0000000000..7f896462b1 --- /dev/null +++ b/app/util/launcher/resources/labels/src/button_text_as_layers.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + exit + info + rec + play + sys + monitor + + diff --git a/app/util/launcher/resources/labels/sys.svg b/app/util/launcher/resources/labels/sys.svg new file mode 100644 index 0000000000..7435102dd7 --- /dev/null +++ b/app/util/launcher/resources/labels/sys.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/app/util/launcher/resources/resources.qrc b/app/util/launcher/resources/resources.qrc index c4bafa3e9f..d945fa31b2 100644 --- a/app/util/launcher/resources/resources.qrc +++ b/app/util/launcher/resources/resources.qrc @@ -1,6 +1,12 @@ ecallauncher.ico - NEURPOLI.TTF + labels/exit.svg + labels/info.svg + labels/logo.svg + labels/monitor.svg + labels/play.svg + labels/rec.svg + labels/sys.svg diff --git a/app/util/launcher/src/about_dialog.cpp b/app/util/launcher/src/about_dialog.cpp index fff5276d43..44512e3dbf 100644 --- a/app/util/launcher/src/about_dialog.cpp +++ b/app/util/launcher/src/about_dialog.cpp @@ -19,9 +19,10 @@ #include "about_dialog.h" -#include +#include #include +#include AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) @@ -29,6 +30,12 @@ AboutDialog::AboutDialog(QWidget *parent) ui_.setupUi(this); ui_.version_label->setText("Version: " + QString("2.3.0")); ui_.ecalversion_label->setText("eCAL " + QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + + ui_.ecal_runtime_version_string_label->setText(QString::fromStdString(eCAL::GetVersionString()) + " (" + QString::fromStdString(eCAL::GetVersionDateString()) + ")"); + ui_.ecal_compiletime_versin_string_label->setText(QString(ECAL_VERSION) + " (" + QString(ECAL_DATE) + ")"); + ui_.qt_runtime_version_string_label->setText(QString(qVersion())); + ui_.qt_compiletime_version_string_label->setText(QString(QT_VERSION_STR)); + connect(ui_.button_box->button(QDialogButtonBox::StandardButton::Ok), SIGNAL(clicked()), this, SLOT(close())); } diff --git a/app/util/launcher/src/about_dialog.ui b/app/util/launcher/src/about_dialog.ui index d9897cbc15..76c692690c 100644 --- a/app/util/launcher/src/about_dialog.ui +++ b/app/util/launcher/src/about_dialog.ui @@ -70,7 +70,6 @@ Advanced Engineering Department Developed by Mihai Muraru - @@ -81,6 +80,68 @@ Developed by Mihai Muraru + + + + + + + Qt runtime version: + + + + + + + qt-runtime-version + + + + + + + eCAL runtime version: + + + + + + + ecal-runtime-version + + + + + + + eCAL compile-time version: + + + + + + + ecal-compiletime-version + + + + + + + Qt compile-time version: + + + + + + + qt-compiletime-version + + + + + + diff --git a/app/util/launcher/src/main.cpp b/app/util/launcher/src/main.cpp index ec0801dfea..795cb6151d 100644 --- a/app/util/launcher/src/main.cpp +++ b/app/util/launcher/src/main.cpp @@ -24,12 +24,10 @@ #include "main_window.h" #include -#include int main(int argc, char *argv[]) { QApplication a(argc, argv); - QFontDatabase::addApplicationFont(":/ecallauncher/APP_FONT"); MainWindow w; w.show(); diff --git a/app/util/launcher/src/main_window.ui b/app/util/launcher/src/main_window.ui index 11ef436d99..d8ad22ad89 100644 --- a/app/util/launcher/src/main_window.ui +++ b/app/util/launcher/src/main_window.ui @@ -43,7 +43,7 @@ Qt::PreventContextMenu - eCALLauncher + eCAL Launcher @@ -130,7 +130,6 @@ - Neuropolitical 11 75 true @@ -164,10 +163,7 @@ QPushButton:!hover {background-color: rgb(0,0,0);color:rgb(255,200,0);padding_bo - Neuropolitical 11 - 50 - false @@ -201,20 +197,18 @@ QPushButton:!hover {background-color: rgb(0,0,0);color:rgb(255,200,0)} - - - - Neuropolitical - 48 - 50 - false - + + + + 16777215 + 90 + - - QLabel {color:rgb(255,200,0)} + + :/ecallauncher/LOGO - - eCAL5 + + false Qt::AlignCenter @@ -274,18 +268,19 @@ QPushButton:!hover {background-color: rgb(0,0,0);color:rgb(255,200,0)} 80 - - - Neuropolitical - 22 - - QPushButton:hover {background-color:rgb(125, 125, 125);color:rgb(0,0,0)} QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} - - monitor + + + :/ecallauncher/LABEL_MONITOR:/ecallauncher/LABEL_MONITOR + + + + 1024 + 30 + @@ -316,15 +311,6 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} 80 - - - Neuropolitical - 22 - 50 - false - false - - Qt::NoFocus @@ -335,11 +321,15 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} QPushButton:hover {background-color:rgb(125, 125, 125);color:rgb(0,0,0)} QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} - - play + + + :/ecallauncher/LABEL_PLAY:/ecallauncher/LABEL_PLAY - - false + + + 1024 + 30 + @@ -376,15 +366,6 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} 50 - - - Neuropolitical - 16 - 50 - false - false - - Qt::NoFocus @@ -398,8 +379,15 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} QPushButton:hover {background-color:rgb(125, 125, 125);color:rgb(0,0,0)} QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} - - info + + + :/ecallauncher/LABEL_INFO:/ecallauncher/LABEL_INFO + + + + 1024 + 20 + false @@ -450,18 +438,19 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} 80 - - - Neuropolitical - 22 - - QPushButton:hover {background-color:rgb(125, 125, 125);color:rgb(0,0,0)} QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} - - sys + + + :/ecallauncher/LABEL_SYS:/ecallauncher/LABEL_SYS + + + + 1024 + 30 + @@ -492,15 +481,6 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} 80 - - - Neuropolitical - 22 - 50 - false - false - - Qt::NoFocus @@ -511,8 +491,15 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} QPushButton:hover {background-color:rgb(125, 125, 125);color:rgb(0,0,0)} QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} - - rec + + + :/ecallauncher/LABEL_REC:/ecallauncher/LABEL_REC + + + + 1024 + 30 + false @@ -549,15 +536,6 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} 50 - - - Neuropolitical - 16 - 50 - false - false - - Qt::NoFocus @@ -568,8 +546,15 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} QPushButton:hover {background-color:rgb(125, 125, 125);color:rgb(0,0,0)} QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} - - exit + + + :/ecallauncher/LABEL_EXIT:/ecallauncher/LABEL_EXIT + + + + 1024 + 20 + false @@ -615,6 +600,10 @@ QPushButton:!hover {background-color:rgb(0,0,0);color:rgb(255,200,0)} + + pushButton_monitor + pushButton_sys + diff --git a/app/util/stop/CMakeLists.txt b/app/util/stop/CMakeLists.txt index 00a098fe98..07d9de336f 100644 --- a/app/util/stop/CMakeLists.txt +++ b/app/util/stop/CMakeLists.txt @@ -30,7 +30,7 @@ target_include_directories(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:PCRE_STATIC;_UNICODE>) -target_link_libraries(${PROJECT_NAME} eCAL::core) +target_link_libraries(${PROJECT_NAME} PRIVATE eCAL::core) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) ecal_install_app(${PROJECT_NAME}) diff --git a/app/util/stop/src/ecal_stop.cpp b/app/util/stop/src/ecal_stop.cpp index b775fe182c..97f93c4208 100644 --- a/app/util/stop/src/ecal_stop.cpp +++ b/app/util/stop/src/ecal_stop.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,13 +26,13 @@ #include -int main(int argc, char** argv) +int main() { // initialize eCAL API - eCAL::Initialize(argc, argv, "eCALStop", eCAL::Init::All); + eCAL::Initialize("eCALStop", eCAL::Init::All); // set process state - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); // some nice info show while collection std::cout << "Collecting local process informations." << std::endl; @@ -46,19 +46,37 @@ int main(int argc, char** argv) } eCAL::Process::SleepMS(500); - // shut down local user processes - std::cout << "--------------------------------------" << std::endl; - std::cout << "Shutdown local eCAL user processes." << std::endl; - std::cout << "--------------------------------------" << std::endl; - eCAL::Util::ShutdownProcesses(); - std::cout << std::endl; + eCAL::Monitoring::SMonitoring monitoring; + eCAL::Monitoring::GetMonitoring(monitoring, eCAL::Monitoring::Entity::Process); + const std::string host_name(eCAL::Process::GetHostName()); - // shut down local eCAL core - std::cout << "--------------------------------------" << std::endl; - std::cout << "Shutdown local eCAL core components." << std::endl; - std::cout << "--------------------------------------" << std::endl; - eCAL::Util::ShutdownCore(); - std::cout << std::endl; + for (const auto& process : monitoring.processes) + { + // filter out eCAL system processes + const std::string uname = process.uname; + if ( (uname != "eCALConfig") + && (uname != "eCALMon") + && (uname != "eCALMon CLI") + && (uname != "eCALMon TUI") + && (uname != "eCALPlay") + && (uname != "eCALPlayGUI") + && (uname != "eCALRec") + && (uname != "eCALRecGUI") + && (uname != "eCALRecClient") + && (uname != "eCALRec-Remote") + && (uname != "eCALRec-Server") + && (uname != "eCALSys") + && (uname != "eCALSysGUI") + && (uname != "eCALSysClient") + && (uname != "eCALSys-Remote") + && (uname != "eCALStop") + && (process.hname == host_name) + ) + { + std::cout << "Stopping process " << process.pname << " (" << process.pid << ")" << std::endl; + eCAL::Util::ShutdownProcess(process.pid); + } + } // finalize eCAL API eCAL::Finalize(); diff --git a/build_linux/clang-tidy/build.sh b/build_linux/clang-tidy/build.sh deleted file mode 100755 index 108b4b2fca..0000000000 --- a/build_linux/clang-tidy/build.sh +++ /dev/null @@ -1,451 +0,0 @@ -#!/bin/bash - -################################################################################ -# # -# This script first runs cmake, and later may run make, and/or clang-tidy # -# either on the compilation database or on selected files. # -# # -# Check help with '-h|--help'. # -# The build path, which is relative to the current script's directory, can be # -# given with the '-b|--build' option. # -# The C and C++ compilers can be set to alternative compilers with the # -# '-o|--compiler' option. # -# With the '-m|--make' option cmake and make runs. # -# With the '-a|--already' option cmake and make does not run, the build is # -# already completed. # -# If not building now or not already built, still 'protoc' will be called to # -# to enable running clang-tidy. # -# With the '-i|--filter' option the paths to the filtering Python application # -# and to its JSON configuration can be given. # -# If the '-d|--database' option is given, it sets the RUN_DATABASE parameter # -# ON. # -# If the '-f|--files' option is given, the rest of the parameters are read as # -# a list of files and the RUN_FILES parameter is set as ON. # -# If the RUN_DATABASE or RUN_FILES option is ON: # -# - the 'compile_commands.json' file is filtered for inc/exc commands, # -# - the excluded commands are saved as 'compile_commands_exc.json', # -# - the original file is renamed as 'compile_commands_orig.json', # -# - the file of included commmands is renamed as 'compile_commands.json', # -# - clang-tidy configuration is dumped to a YAML file, # -# - if required protobuf will be called. # -# If the RUN_DATABASE option is ON: # -# - clang-tidy runs with the filtered 'compile_commands.json' database. # -# If the RUN_FILES option is ON: # -# - file extensions are checked for relevance, # -# - file paths are checked for excluded directories, # -# - after these checks the files are analyzed by clang-tidy one-by-one. # -# Outputs are redirected into timestamped log files, 'log_*.txt', in the build # -# directory as well. # -# # -################################################################################ - -# exit at the first error -set -e - -RUN_MAKE='OFF' -RUN_DATABASE='OFF' -RUN_FILES='OFF' -GEN_FILES='ON' - -EXT_PATTERN='^(cpp|cppm|ixx|cxx|cc|c|h|hh|hxx|hpp)$' -PATH_BUILD='../../_build' -DIR_BUILD= -DIR_SCRIPT= -DIR_ROOT= -PATH_FILTER='filter_clang_tidy.py' -PATH_EXC_CONFIG='excludes_clang_tidy.json' -CMAKE_BUILD_TYPE='Release' -NUM_INST=4 -DATE_TIME=$(date +"%Y-%m-%d_%H-%M-%S") -FILE_MAKE_OUTPUT="make_log_${DATE_TIME}.txt" -FILE_CLANG_TIDY_OUTPUT="clang_tidy_log_${DATE_TIME}.txt" -FILE_CLANG_TIDY_CONFIG='config_clang_tidy.yml' -# optionally specify with version number, for example: 'clang-tidy-14' -CLANG_TIDY='clang-tidy' -SEP_1=$(printf "%0.s=" {1..80}) -SEP_2=$(printf "%0.s-" {1..80}) -declare -a FILE_LIST -declare -a EXC_LIST - -# leave empty for default values -DCMAKE_EXPORT_COMPILE_COMMANDS= #'-DCMAKE_EXPORT_COMPILE_COMMANDS=ON' -DCMAKE_C_COMPILER= #'-DCMAKE_C_COMPILER=/usr/bin/clang-14' -DCMAKE_CXX_COMPILER= #'-DCMAKE_CXX_COMPILER=/usr/bin/clang++-14' - -# ------------------------------------------------------------------------------ - -USAGE="$(basename "$0") [-h|-help] [-b|--build ] [-c|compiler ] [-m|--make] [-i|--filter ] [-d|--database] [-a|--already] [-f|--files ] -run cmake, and then optionally make and/or clang-tidy - where: - -h | --help show this help message and exit - -b | --build build path relative to this script, default: '${PATH_BUILD}' - -c | --compiler set C & CXX compiler paths - -m | --make run make - -i | --filter filtering app & its config rel. to this script or abs. paths, default: '${PATH_FILTER}' '${PATH_EXC_CONFIG}' - -d | --database run clang-tidy on the compilation database - -a | --already already built, all machine-generated codes are available - -f | --files run clang-tidy on the given files (remaining args) -" - -if [[ $# -ge 1 ]] -then - while true - do - case "$1" in - -h | --help ) echo -e "${USAGE}" ; shift ; exit 0 ;; - -b | --build ) if [[ $# -lt 2 ]];then echo "ERROR - missing build path arg" ; exit 1 ; fi ; - PATH_BUILD="$2" ; shift 2 ; - if [[ $# -eq 0 ]];then break ; fi ;; - -c | --compiler ) if [[ $# -lt 3 ]];then echo "ERROR - missing compiler args" ; exit 1 ; fi ; - DCMAKE_C_COMPILER="-DCMAKE_C_COMPILER=$2" ; - DCMAKE_CXX_COMPILER="-DCMAKE_CXX_COMPILER=$3" ; - shift 3 ; if [[ $# -eq 0 ]];then break ; fi ;; - -m | --make ) RUN_MAKE='ON' ; shift ; - if [[ $# -eq 0 ]];then break ; fi ;; - -i | --filter ) if [[ $# -lt 3 ]];then echo "ERROR - missing filtering path arg" ; exit 1 ; fi ; - PATH_FILTER="$2" ; PATH_EXC_CONFIG="$3" ; - shift 3 ; if [[ $# -eq 0 ]];then break ; fi ;; - -d | --database ) RUN_DATABASE='ON' ; shift ; - if [[ $# -eq 0 ]];then break ; fi ;; - -a | --already ) GEN_FILES='OFF' ; shift ; - if [[ $# -eq 0 ]];then break ; fi ;; - -f | --files ) RUN_FILES='ON' ; shift ; - if [[ $# -eq 0 ]];then echo "WARNING - missing file list" ; exit 0 ; fi ; - FILE_LIST=("$@") ; break ;; - * ) echo "ERROR - unknown option: '$1'" ; shift ; exit 1 ;; - esac - done -fi - -# ------------------------------------------------------------------------------ - -find_root_dir() { - local path='' - - while true - do - if [[ -d '.git' ]] - then - path=$(pwd) - break - else - cd .. - fi - done - - echo "${path}" -} - -check_args() { - # cd to script's directory - cd "${0%/*}" - DIR_SCRIPT=$(pwd) - - # detect relative path by removing the final '/' and all trailing chars '*' - local dir_rel=${PATH_BUILD%/*} - local root_dir_git - local path_clang_tidy - - DIR_BUILD_NAME=${PATH_BUILD#"${dir_rel}"/} - cd "${dir_rel}" - DIR_BUILD_ROOT=$(pwd) - DIR_BUILD="${DIR_BUILD_ROOT}/${DIR_BUILD_NAME}" - - # find the root directory where '.git/' resides - cd "${DIR_SCRIPT}" - root_dir_git=$(find_root_dir) - cd "${root_dir_git}" - DIR_ROOT=$(pwd) - - if [[ "${RUN_DATABASE}" == 'ON' || "${RUN_FILES}" == 'ON' ]] - then - set +e - path_clang_tidy=$(command -v ${CLANG_TIDY}) - set -e - if [[ -z ${path_clang_tidy} ]] - then - echo -e "FATAL: ${CLANG_TIDY} is not available" - exit 1 - fi - fi - - if [[ "${RUN_DATABASE}" == 'ON' && "${RUN_FILES}" == 'ON' ]] - then - RUN_DATABASE='OFF' - fi - - echo "++ run clang-tidy on the compilation database: ${RUN_DATABASE}" - echo "++ run clang-tidy on the given files : ${RUN_FILES}" - - if [[ "${RUN_DATABASE}" == 'ON' || "${RUN_FILES}" == 'ON' ]] - then - DCMAKE_EXPORT_COMPILE_COMMANDS='-DCMAKE_EXPORT_COMPILE_COMMANDS=ON' - ( set -x ; ${CLANG_TIDY} --version ) - fi -} - -run_cmake() { - if [[ "${GEN_FILES}" == 'ON' ]] - then - echo "++ build type: ${CMAKE_BUILD_TYPE}" - echo -e "\n++ running cmake ..." - - rm -rf "${DIR_BUILD:?}/" - mkdir -p "${DIR_BUILD}" - cd "${DIR_BUILD}" - - cmake "${DIR_ROOT}" "${DCMAKE_EXPORT_COMPILE_COMMANDS}" \ - "${DCMAKE_C_COMPILER}" \ - "${DCMAKE_CXX_COMPILER}" \ - "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" \ - -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF \ - -DECAL_THIRDPARTY_BUILD_CURL=OFF \ - -DECAL_THIRDPARTY_BUILD_HDF5=OFF - fi -} - -run_make() { - if [[ "${RUN_MAKE}" == 'ON' ]] - then - GEN_FILES='OFF' - cd "${DIR_BUILD}" - local cmd="cmake --build . -- -j${NUM_INST}" - echo -e "\n++ ${cmd}\nsee: ${FILE_MAKE_OUTPUT}" - echo "${cmd}" >> "${FILE_MAKE_OUTPUT}" - time ${cmd} |& tee -a "${FILE_MAKE_OUTPUT}" - fi -} - -# searched for in the output of 'make --debug=b all' -run_protoc() { - echo -e "\n++ running protoc ..." - make -f ecal/pb/CMakeFiles/pb.dir/build.make ecal/pb/CMakeFiles/pb.dir/depend - make -f samples/cpp/measurement/measurement_read/CMakeFiles/measurement_read.dir/build.make samples/cpp/measurement/measurement_read/CMakeFiles/measurement_read.dir/depend - make -f samples/cpp/measurement/measurement_write/CMakeFiles/measurement_write.dir/build.make samples/cpp/measurement/measurement_write/CMakeFiles/measurement_write.dir/depend - make -f samples/cpp/multiple/multiple_rec_cb/CMakeFiles/multiple_rec_cb.dir/build.make samples/cpp/multiple/multiple_rec_cb/CMakeFiles/multiple_rec_cb.dir/depend - make -f samples/cpp/multiple/multiple_snd/CMakeFiles/multiple_snd.dir/build.make samples/cpp/multiple/multiple_snd/CMakeFiles/multiple_snd.dir/depend - make -f samples/cpp/person/person_rec/CMakeFiles/person_rec.dir/build.make samples/cpp/person/person_rec/CMakeFiles/person_rec.dir/depend - make -f samples/cpp/person/person_rec_events/CMakeFiles/person_rec_events.dir/build.make samples/cpp/person/person_rec_events/CMakeFiles/person_rec_events.dir/depend - make -f samples/cpp/person/person_rec_lambda_in_class/CMakeFiles/person_rec_lambda_in_class.dir/build.make samples/cpp/person/person_rec_lambda_in_class/CMakeFiles/person_rec_lambda_in_class.dir/depend - make -f samples/cpp/person/person_snd/CMakeFiles/person_snd.dir/build.make samples/cpp/person/person_snd/CMakeFiles/person_snd.dir/depend - make -f samples/cpp/person/person_snd_dyn/CMakeFiles/person_snd_dyn.dir/build.make samples/cpp/person/person_snd_dyn/CMakeFiles/person_snd_dyn.dir/depend - make -f samples/cpp/person/person_snd_events/CMakeFiles/person_snd_events.dir/build.make samples/cpp/person/person_snd_events/CMakeFiles/person_snd_events.dir/depend - make -f samples/cpp/person/person_snd_inproc/CMakeFiles/person_snd_inproc.dir/build.make samples/cpp/person/person_snd_inproc/CMakeFiles/person_snd_inproc.dir/depend - make -f samples/cpp/person/person_snd_multicast/CMakeFiles/person_snd_multicast.dir/build.make samples/cpp/person/person_snd_multicast/CMakeFiles/person_snd_multicast.dir/depend - make -f samples/cpp/person/person_snd_tcp/CMakeFiles/person_snd_tcp.dir/build.make samples/cpp/person/person_snd_tcp/CMakeFiles/person_snd_tcp.dir/depend - make -f samples/cpp/services/math_client/CMakeFiles/math_client.dir/build.make samples/cpp/services/math_client/CMakeFiles/math_client.dir/depend - make -f samples/cpp/services/math_server/CMakeFiles/math_server.dir/build.make samples/cpp/services/math_server/CMakeFiles/math_server.dir/depend - make -f samples/cpp/services/ping_client/CMakeFiles/ping_client.dir/build.make samples/cpp/services/ping_client/CMakeFiles/ping_client.dir/depend - make -f samples/cpp/services/ping_server/CMakeFiles/ping_server.dir/build.make samples/cpp/services/ping_server/CMakeFiles/ping_server.dir/depend -} - -filter_compile_commands() { - if [[ "${RUN_DATABASE}" == 'ON' || "${RUN_FILES}" == 'ON' ]] - then - echo -e "\n++ filtering the compile commands ..." - cd "${DIR_SCRIPT}" - echo "excluded directories:" - cat "$PATH_EXC_CONFIG" - python3 "${PATH_FILTER}" --build "${DIR_BUILD}" - - cp -a "${DIR_ROOT}/.clang-tidy" "${DIR_BUILD}" - cd "${DIR_BUILD}" - ${CLANG_TIDY} --dump-config > ${FILE_CLANG_TIDY_CONFIG} - - # use the included commands as compile commands - mv compile_commands.json compile_commands_orig.json - mv compile_commands_inc.json compile_commands.json - - # for protobuf generated source & header files, protoc is fast - # if built with this script (-m) or built already (-a), then there is no need to call protoc - if [[ "${GEN_FILES}" == 'ON' ]] - then - run_protoc - fi - fi -} - -run_clang_tidy_on_database() { - if [[ "${RUN_DATABASE}" == 'ON' ]] - then - # see: run-clang-tidy --help - local cmd="run-${CLANG_TIDY} -j${NUM_INST}" - echo -e "\n++ ${cmd}\ncfg: ${FILE_CLANG_TIDY_CONFIG}\nsee: ${FILE_CLANG_TIDY_OUTPUT}" - echo "${cmd}" >> "${FILE_CLANG_TIDY_OUTPUT}" - time ${cmd} |& tee -a "${FILE_CLANG_TIDY_OUTPUT}" - fi -} - -# ASSUMPTION: JSON is well-formed and pretty-printed. -# if empty: -# [] -# else (for example): -# [ -# ["a", "b"], -# ["c"] -# ] -read_config_basic() { - local line_count - local line_trim - local line_no_quotes - local line_no_brackets - local subdir - - cd "${DIR_SCRIPT}" - if [[ -f "$PATH_EXC_CONFIG" ]] - then - line_count=$(wc -l < "$PATH_EXC_CONFIG") - if [[ "${line_count}" -gt "1" ]] - then - declare -a exc_dirs - while IFS= read -r line - do - exc_dirs[${#exc_dirs[@]}]="$line" - done < "$PATH_EXC_CONFIG" - # eliminate the first and the last element, '[' and ']' respectively - unset 'exc_dirs[0]' - unset 'exc_dirs[-1]' - for exc_dir in "${exc_dirs[@]}" - do - line_trim=$(echo "${exc_dir}" | tr -d '[:space:]') - line_no_quotes=$(echo "${line_trim}" | tr -d '"') - line_no_brackets=$(echo "${line_no_quotes}" | tr -d '[]') - declare -a dirs - IFS=',' read -ar dirs <<< "${line_no_brackets}" - subdir=$(printf "/%s" "${dirs[@]}") - EXC_LIST[${#EXC_LIST[@]}]="${subdir}/" - done - else - echo "WARNING: JSON for exclusion list is empty" - fi - else - echo "FATAL: config file does not exist" - exit 1 - fi -} - -# jq can parse valid JSONs, pretty-print is not required. -read_config() { - local path_jq - local subdir - - cd "${DIR_SCRIPT}" - set +e - path_jq=$(command -v jq) - set -e - if [[ -z ${path_jq} ]] - then - echo -e "WARNING: 'jq' is not available, fallig back to the simple Bash JSON parser" - read_config_basic - else - if [[ -f "$PATH_EXC_CONFIG" ]] - then - for row in $(jq -c '.[]' < "${PATH_EXC_CONFIG}") - do - subdir='' - for dir in $(echo "${row}" | jq -r '.[]') - do - subdir="${subdir}/${dir}" - done - EXC_LIST[${#EXC_LIST[@]}]="${subdir}/" - done - else - echo "FATAL: config file does not exist" - exit 1 - fi - fi -} - -is_excluded() { - local path="$1" - for subdir in "${EXC_LIST[@]}" - do - if [[ "${path}" =~ .*"${subdir}".* ]] - then - true - return - fi - done - false - return -} - -run_clang_tidy_on_files() { - if [[ "${RUN_FILES}" == 'ON' ]] - then - local file_abs - local file_char - local file_base - local file_name - local file_ext - - read_config - - cd "${DIR_BUILD}" - # see: clang-tidy --help - echo -e "\n++ analyzing source files by clang-tidy ..." - printf -- "-- %s\n" "${FILE_LIST[@]}" - echo - - for file in "${FILE_LIST[@]}" - do - file_abs="${file}" - file_char="${file_abs:0:1}" - - if [[ ${file_char} != '/' ]] - then - file_abs="${DIR_ROOT}/${file}" - fi - - file_base=$(basename "${file_abs}") - file_name="${file_base%.*}" - file_ext="${file_base##*.}" - - echo "${SEP_1}" - echo -e "-- ${file}\n ${file_name} . ${file_ext}" - - # existing? - if [[ -f "${file_abs}" ]] - then - # if 1. the file is by its extension a C++-related one - # 2. its path does not contain any excluded directories - # then analyze it by clang-tidy - if [[ "${file_ext}" =~ $EXT_PATTERN ]] - then - if is_excluded "${file_abs}" - then - echo "## excluded" - else - # if 'compile_commands.json' is unreachable, clang-tidy gives the following error: - # "Error while trying to load a compilation database: ..." - local cmd="${CLANG_TIDY} -p . ${file_abs}" - echo "## analyzing" - echo "${SEP_2}" - echo "${cmd}" |& tee -a "${FILE_CLANG_TIDY_OUTPUT}" - ${cmd} |& tee -a "${FILE_CLANG_TIDY_OUTPUT}" - echo "${SEP_2}" >> "${FILE_CLANG_TIDY_OUTPUT}" - fi - else - echo "## skipping" - fi - else - echo "## not existing" - fi - done - echo "${SEP_1}" - fi -} - -# ------------------------------------------------------------------------------ - -check_args -run_cmake -run_make -filter_compile_commands -run_clang_tidy_on_database -run_clang_tidy_on_files - -# for GitHub actions -# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions -echo "::set-output name=timestamp::${DATE_TIME}" - -echo -e "\n++ completed" diff --git a/build_linux/clang-tidy/excludes_clang_tidy.json b/build_linux/clang-tidy/excludes_clang_tidy.json deleted file mode 100644 index 2f8c3f0e71..0000000000 --- a/build_linux/clang-tidy/excludes_clang_tidy.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - ["_build"], - ["thirdparty"] -] diff --git a/build_linux/clang-tidy/filter_clang_tidy.py b/build_linux/clang-tidy/filter_clang_tidy.py deleted file mode 100644 index a7b3c504d6..0000000000 --- a/build_linux/clang-tidy/filter_clang_tidy.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -Filter compilation database so that undesired CPP and H files are excluded from clang-tidy's output. -Its default configuration file is 'excludes_clang_tidy.json'. - -This script processes the 'compile_commands.json' file which CMake can generate since v2.8.5. -`JSON Compilation Database Format Specification `__ - -The CPP files whose paths contain the directories given by 'excludes_clang_tidy.json' are filtered out. -The filtering results in two JSON files, one for included and one for excluded commands. -H files located in this directories may optionally be included as '-isystem' instead of '-I', -so that they are excluded from static analysis as well. -""" - -import argparse -import json -import os -import sys -import re - -# ------------------------------------------------------------------------------ - -DEBUG = False -GRACEFUL_EXIT = False -DEF_BUILD = '../../_build' -DEF_CONFIG = 'excludes_clang_tidy.json' -DEF_ISYSTEM = False - -path_config = '' -path_build = '' -isystem = DEF_ISYSTEM -commands = [] -excludes = [] -commands_inc = [] -commands_exc = [] - -# ------------------------------------------------------------------------------ - -def read_args(): - """ - Parse arguments with the 'argparse' module: - `argparse — Parser for command-line options, arguments and sub-commands `__ - Check help with '-h|--help'. - Relative paths are relative to the current script's location. - """ - global path_build - global path_config - global isystem - - # display default values - parser = argparse.ArgumentParser(description='Filter compilation database.', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument('--build', - help='rel to this script/abs path of the build directory', - default=DEF_BUILD) - parser.add_argument('--config', - help='rel to this script/abs path of the config JSON file', - default=DEF_CONFIG) - parser.add_argument('--isystem', - action='store_true', - help='convert includes from -I to -isystem', - default=DEF_ISYSTEM) - - args = parser.parse_args() - build = args.build - config = args.config - isystem = args.isystem - - if DEBUG: - print(f'arg :: build = "{build}"') - print(f'arg :: config = "{config}"') - print(f'arg :: isystem = {isystem}') - - # first change working directory to script's directory - os.chdir(os.path.dirname(os.path.abspath(sys.argv[0]))) - path_script = os.getcwd() - - if os.path.isabs(build): - path_build = build - else: - path_build = os.path.realpath(os.path.join(path_script, build)) - - if os.path.isabs(config): - path_config = config - else: - path_config = os.path.realpath(os.path.join(path_script, config)) - -def read_config(): - """ - Read the configuration file for excluded directories. - Each member of the array itself is an array of directory names relative to the root directory. - These names are concatenated into proper subdirectory parts. - These strings are then searched for in the commands array. - """ - global excludes - - if not os.path.exists(path_config): - if GRACEFUL_EXIT: - print(f'** ERROR - directory exclusion configuration is missing:\n{path_config}') - sys.exit(0) - else: - raise SystemExit(f'** FATAL - directory exclusion configuration is missing:\n{path_config}') - - with open(path_config, 'r') as excludes_file: - excludes_raw = json.load(excludes_file) - for exclude_raw in excludes_raw: - exclude = os.path.sep.join(exclude_raw) - excludes.append(exclude) - if DEBUG: - print('EXCLUDED DIRECTORIES:') - print(json.dumps(excludes, indent = 4, ensure_ascii=False, sort_keys=False)) - -def read_commands(): - """ - Read the 'compile_commands.json' file generated by CMake. - """ - global commands - - path_database = os.path.join(path_build, 'compile_commands.json') - if not os.path.exists(path_database): - if GRACEFUL_EXIT: - print(f'** ERROR - CMake-generated compilation database is missing:\n{path_database}') - sys.exit(0) - else: - raise SystemExit(f'** FATAL - CMake-generated compilation database is missing:\n{path_database}') - - with open(path_database, 'r') as cmake_gen_file: - commands = json.load(cmake_gen_file) - - if DEBUG: - print('COMPILE COMMANDS:') - print(json.dumps(commands, indent = 4, ensure_ascii=False, sort_keys=False)) - -def filter_sources(): - """ - In the commands array, using the excluded directory strings, the 'file' key is used to filter the commands. - Therefore the JSON array is separated into two JSON arrays. - """ - for command in commands: - if DEBUG: - print(command['file']) - - path_str = os.path.dirname(command['file']) - include_folder = True - for exclude in excludes: - if f'{os.path.sep}{exclude}{os.path.sep}' in path_str: - include_folder = False - break - - if include_folder: - if DEBUG: - print('++ included') - commands_inc.append(command) - else: - if DEBUG: - print('-- excluded') - commands_exc.append(command) - -def filter_headers(): - """ - Clang-tidy scans headers with "HeaderFilterRegex: '.*' configuration more deeply. - Although theoretically it is possible to use CMake facilities, a pragmatic solution - to undesired header processing is to replace plain includes with system includes. - During the static analysis system headers are ignored unless stated otherwise. - """ - if isystem: - for command in commands_inc: - path_str = command['command'] - for exclude in excludes: - path_mod = re.subn(rf'\s?-I(\S*{os.path.sep}{exclude}{os.path.sep}\S*)\s?', r' -isystem \1 ', path_str) - if path_mod[1] > 0: - if DEBUG: - print(f"-- {path_str}") - command['command'] = path_mod[0] - if DEBUG: - print(f"++ {path_mod[1]} replacements:\n++ {path_mod[0]}") - -def save_commands(): - """ - Save two JSON files, one for included and one for excluded commands. - Line counts of these files must match the original commands, minus the extra '[' and ']' lines. - """ - path_compile_commands_inc = os.path.join(path_build, 'compile_commands_inc.json') - path_compile_commands_exc = os.path.join(path_build, 'compile_commands_exc.json') - - with open(path_compile_commands_inc, 'w') as commands_inc_json: - json.dump(commands_inc, commands_inc_json, indent=4, ensure_ascii=False, sort_keys=False) - - with open(path_compile_commands_exc, 'w') as commands_exc_json: - json.dump(commands_exc, commands_exc_json, indent=4, ensure_ascii=False, sort_keys=False) - -def main(): - read_args() - read_config() - read_commands() - filter_sources() - filter_headers() - save_commands() - -if __name__ == '__main__': - main() diff --git a/build_win/Readme.md b/build_win/Readme.md index 7bdf91ff03..07b4f947ea 100644 --- a/build_win/Readme.md +++ b/build_win/Readme.md @@ -1,4 +1,4 @@ -If you want to build complete eCAL setup for windows then simply call. +If you want to build complete eCAL setup for windows then simply call: ```bash win_make_all.bat @@ -11,3 +11,9 @@ win_make_cmake.bat win_make_build.bat win_make_setup.bat ``` + +If you want to create a python wheel call: + +```bash +win_make_python.bat +``` diff --git a/build_win/download_npcap.ps1 b/build_win/download_npcap.ps1 deleted file mode 100644 index 39d73e2458..0000000000 --- a/build_win/download_npcap.ps1 +++ /dev/null @@ -1,9 +0,0 @@ - -$target_dir = "$PSScriptRoot\..\thirdparty\npcap\" - -New-Item "$target_dir" -ItemType "directory" -Force - -$webclient = New-Object System.Net.WebClient - -$webclient.DownloadFile("https://npcap.com/dist/npcap-sdk-1.13.zip","$target_dir\npcap-sdk.zip") -$webclient.DownloadFile("https://github.com/seladb/PcapPlusPlus/releases/download/v22.05/pcapplusplus-22.05-windows-vs2015.zip","$target_dir\pcapplusplus.zip") \ No newline at end of file diff --git a/build_win/nanopb/compile-nanopb.bat b/build_win/nanopb/compile-nanopb.bat new file mode 100644 index 0000000000..fdbf4f4589 --- /dev/null +++ b/build_win/nanopb/compile-nanopb.bat @@ -0,0 +1 @@ +python compile-nanopb.py --nano_pb_path c:\nanopb\nanopb-0.4.9 --ecal_repository "..\.." \ No newline at end of file diff --git a/build_win/nanopb/compile-nanopb.py b/build_win/nanopb/compile-nanopb.py new file mode 100644 index 0000000000..5632fc90e0 --- /dev/null +++ b/build_win/nanopb/compile-nanopb.py @@ -0,0 +1,112 @@ +import sys +import re +import subprocess +import logging +from pathlib import Path +import shutil +import argparse + +def setup_logging(): + """Sets up the logging configuration.""" + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + + +def list_files(directory: Path, extension: str) -> list[Path]: + """Returns a list of files with specific extension in the given directory.""" + if not directory.exists(): + logging.error(f"Directory {directory} does not exist.") + return [] + return list(directory.glob(f"*{extension}")) + + +def copy_files(source_dir: Path, target_dir: Path, file_types: list[str]): + """Copies files of specific types from source to target directory.""" + target_dir.mkdir(parents=True, exist_ok=True) + for file_type in file_types: + for file in source_dir.glob(file_type): + try: + shutil.copy2(file, target_dir) + logging.info(f"Copied {file.name} to {target_dir}") + except Exception as e: + logging.error(f"Error copying {file.name} to {target_dir}: {e}") + + +def check_nanopb_compiler_exists(compiler_path: Path): + """Checks if the nanopb_generator exists.""" + if not compiler_path.exists(): + logging.error(f"nanopb generator not found at {compiler_path}") + sys.exit(1) + + +def run_nanopb_generator(proto_files: list[Path], compiler: Path, ecal_pb_base_path: Path, ecal_pb_sub_path: Path, target_dir: Path): + """Runs the nanopb generator for each proto file.""" + for proto_file_path in proto_files: + proto_file_name = proto_file_path.name + + command = [ + str(compiler), + "-I" + str(ecal_pb_base_path), + "-I" + str(ecal_pb_base_path / ecal_pb_sub_path), + "-D" + str(target_dir / ecal_pb_sub_path), + "-e" + ".npb", + proto_file_name + ] + + logging.info(f"Running: {' '.join(command)}") + + try: + result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, cwd=proto_file_path.parent) + logging.info(f"Success: {proto_file_name} processed.") + logging.debug(result.stdout) + except subprocess.CalledProcessError as e: + logging.error(f"Error running nanopb_generator for {proto_file_name}: {e.stderr}") + + +def main(nano_pb_path: Path, ecal_repository: Path): + setup_logging() + + # Define paths based on the provided arguments + ecal_pb_base_path = Path(ecal_repository / "ecal/core_pb/src") + ecal_pb_sub_path = Path("ecal/core/pb") + ecal_target_path = Path("../../core/src/serialization/nanopb") + + # Combine paths and list .proto files + proto_files_dir = ecal_pb_base_path / ecal_pb_sub_path + ecal_pb_files = list_files(proto_files_dir, ".proto") + + # Check if nanopb generator exists + nano_pb_compiler = nano_pb_path / "generator-bin/nanopb_generator.exe" + check_nanopb_compiler_exists(nano_pb_compiler) + + # Check if any .proto files are found + if not ecal_pb_files: + logging.error(f"No .proto files found in {proto_files_dir}") + sys.exit(1) + + # Prepare target directory + absolute_target_path = (ecal_pb_base_path / ecal_target_path).resolve() + absolute_target_path.mkdir(parents=True, exist_ok=True) + + # Copy nanopb common decoder and encoder to target nanopb directory + target_nanopb_dir = absolute_target_path + copy_files(nano_pb_path, target_nanopb_dir, ["*.c", "*.h"]) + + # Run nanopb_generator for each .proto file + run_nanopb_generator(ecal_pb_files, nano_pb_compiler, ecal_pb_base_path, ecal_pb_sub_path, absolute_target_path) + + +if __name__ == "__main__": + # Set up argument parsing + parser = argparse.ArgumentParser(description="Process nanopb and eCAL protobuf files.") + parser.add_argument("--nano_pb_path", type=Path, required=True, help="Path to the nanopb directory") + parser.add_argument("--ecal_repository", type=Path, required=True, help="Path to the eCAL repository") + + # Parse the arguments + args = parser.parse_args() + + # Resolve paths to absolute paths to support relative paths + nano_pb_path = Path(args.nano_pb_path).resolve() + ecal_repository = Path(args.ecal_repository).resolve() + + # Call the main function with resolved absolute paths + main(nano_pb_path, ecal_repository) \ No newline at end of file diff --git a/build_win/win_make_all.bat b/build_win/win_make_all.bat index ae12a54e14..beb5c9ea81 100644 --- a/build_win/win_make_all.bat +++ b/build_win/win_make_all.bat @@ -5,6 +5,5 @@ pushd %~dp0\.. call build_win\win_make_cmake.bat call build_win\win_make_build.bat call build_win\win_make_setup.bat -call build_win\win_make_python_wheel.bat popd diff --git a/build_win/win_make_cmake.bat b/build_win/win_make_cmake.bat index 3ef8f4f373..353d3cc02c 100644 --- a/build_win/win_make_cmake.bat +++ b/build_win/win_make_cmake.bat @@ -4,12 +4,10 @@ pushd "%~dp0\.." call build_win\win_set_vars.bat -echo Downloading NPCAP -powershell -Command "& '%~dp0\download_npcap.ps1'" - set CMAKE_OPTIONS_COMPLETE=-DCMAKE_INSTALL_PREFIX=_install ^ +-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake ^ -DHAS_HDF5=ON ^ --DHAS_QT5=ON ^ +-DHAS_QT=ON ^ -DHAS_CURL=ON ^ -DHAS_CAPNPROTO=OFF ^ -DHAS_FTXUI=ON ^ @@ -17,16 +15,13 @@ set CMAKE_OPTIONS_COMPLETE=-DCMAKE_INSTALL_PREFIX=_install ^ -DBUILD_APPS=ON ^ -DBUILD_SAMPLES=ON ^ -DBUILD_TIME=ON ^ --DBUILD_PY_BINDING=ON ^ +-DBUILD_PY_BINDING=OFF ^ -DBUILD_CSHARP_BINDING=ON ^ -DBUILD_ECAL_TESTS=ON ^ --DECAL_INCLUDE_PY_SAMPLES=OFF ^ -DECAL_INSTALL_SAMPLE_SOURCES=ON ^ --DECAL_JOIN_MULTICAST_TWICE=OFF ^ -DECAL_NPCAP_SUPPORT=ON ^ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON ^ -DECAL_THIRDPARTY_BUILD_PROTOBUF=ON ^ --DECAL_THIRDPARTY_BUILD_SPDLOG=ON ^ -DECAL_THIRDPARTY_BUILD_TINYXML2=ON ^ -DECAL_THIRDPARTY_BUILD_FINEFTP=ON ^ -DECAL_THIRDPARTY_BUILD_CURL=ON ^ @@ -35,15 +30,15 @@ set CMAKE_OPTIONS_COMPLETE=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_THIRDPARTY_BUILD_RECYCLE=ON ^ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON ^ -DECAL_THIRDPARTY_BUILD_QWT=ON ^ --DECAL_THIRDPARTY_BUILD_YAML-CPP=ON ^ -DECAL_THIRDPARTY_BUILD_UDPCAP=ON ^ -DBUILD_SHARED_LIBS=OFF ^ -DCMAKE_BUILD_TYPE=Release ^ -DCPACK_PACK_WITH_INNOSETUP=ON set CMAKE_OPTIONS_SDK=-DCMAKE_INSTALL_PREFIX=_install ^ +-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake ^ -DHAS_HDF5=ON ^ --DHAS_QT5=ON ^ +-DHAS_QT=ON ^ -DHAS_CURL=OFF ^ -DHAS_CAPNPROTO=OFF ^ -DHAS_FTXUI=ON ^ @@ -54,13 +49,10 @@ set CMAKE_OPTIONS_SDK=-DCMAKE_INSTALL_PREFIX=_install ^ -DBUILD_PY_BINDING=OFF ^ -DBUILD_CSHARP_BINDING=OFF ^ -DBUILD_ECAL_TESTS=OFF ^ --DECAL_INCLUDE_PY_SAMPLES=OFF ^ -DECAL_INSTALL_SAMPLE_SOURCES=OFF ^ --DECAL_JOIN_MULTICAST_TWICE=OFF ^ -DECAL_NPCAP_SUPPORT=ON ^ -DECAL_THIRDPARTY_BUILD_CMAKE_FUNCTIONS=ON ^ -DECAL_THIRDPARTY_BUILD_PROTOBUF=ON ^ --DECAL_THIRDPARTY_BUILD_SPDLOG=ON ^ -DECAL_THIRDPARTY_BUILD_TINYXML2=ON ^ -DECAL_THIRDPARTY_BUILD_FINEFTP=OFF ^ -DECAL_THIRDPARTY_BUILD_CURL=OFF ^ @@ -69,7 +61,6 @@ set CMAKE_OPTIONS_SDK=-DCMAKE_INSTALL_PREFIX=_install ^ -DECAL_THIRDPARTY_BUILD_RECYCLE=ON ^ -DECAL_THIRDPARTY_BUILD_TCP_PUBSUB=ON ^ -DECAL_THIRDPARTY_BUILD_QWT=OFF ^ --DECAL_THIRDPARTY_BUILD_YAML-CPP=OFF ^ -DECAL_THIRDPARTY_BUILD_UDPCAP=ON ^ -DBUILD_SHARED_LIBS=OFF ^ -DCMAKE_BUILD_TYPE=Debug ^ diff --git a/build_win/win_make_python_wheel.bat b/build_win/win_make_python_wheel.bat index 743abf3985..0736dff9f3 100644 --- a/build_win/win_make_python_wheel.bat +++ b/build_win/win_make_python_wheel.bat @@ -4,8 +4,23 @@ pushd %~dp0\.. call build_win\win_set_vars.bat -cd /d %BUILD_DIR_COMPLETE% +if not exist "%BUILD_DIR_COMPLETE%" mkdir "%BUILD_DIR_COMPLETE%" -cmake --build . --target create_python_wheel --config Release +echo Creating Python venv +if not exist "%BUILD_DIR_COMPLETE%\.venv" mkdir "%BUILD_DIR_COMPLETE%\.venv" +python -m venv "%BUILD_DIR_COMPLETE%\.venv" +CALL "%BUILD_DIR_COMPLETE%\.venv\Scripts\activate.bat" + +echo Upgrading pip +python -m pip install --upgrade pip + +echo Installing python requirements +pip install wheel +pip install -r doc\requirements.txt +python -m pip install build + +cd /d "%WORKSPACE%\%BUILD_DIR_COMPLETE%" + +python -m build ..\.. --outdir .\_deploy popd diff --git a/cmake/Modules/Findsimpleini.cmake b/cmake/Modules/Findsimpleini.cmake deleted file mode 100644 index 4954f158fe..0000000000 --- a/cmake/Modules/Findsimpleini.cmake +++ /dev/null @@ -1,24 +0,0 @@ -find_path(simpleini_INCLUDE_DIR - NAMES SimpleIni.h -) - -if(simpleini_INCLUDE_DIR-NOTFOUND) - message(FATAL_ERROR "Could not find simpleini library") - set(simpleini_FOUND FALSE) -else() - set(simpleini_FOUND TRUE) -endif() - -if(simpleini_FOUND) - include(FindPackageHandleStandardArgs) - find_package_handle_standard_args(simpleini - REQUIRED_VARS simpleini_INCLUDE_DIR) - - if(NOT TARGET simpleini::simpleini) - set(simpleini_INCLUDE_DIRS ${simpleini_INCLUDE_DIR}) - add_library(simpleini::simpleini INTERFACE IMPORTED) - set_target_properties(simpleini::simpleini PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES ${simpleini_INCLUDE_DIR}) - mark_as_advanced(simpleini_INCLUDE_DIR) - endif() -endif() diff --git a/cmake/helper_functions/ecal_add_functions.cmake b/cmake/helper_functions/ecal_add_functions.cmake index 8c48d47139..089c46c5ff 100644 --- a/cmake/helper_functions/ecal_add_functions.cmake +++ b/cmake/helper_functions/ecal_add_functions.cmake @@ -16,6 +16,10 @@ # # ========================= eCAL LICENSE ================================= +include_guard(GLOBAL) + +include("${CMAKE_CURRENT_LIST_DIR}/ecal_compiler_warnings.cmake") + # This function will set the output names of the target according to eCAL conventions. function(ecal_add_app_console TARGET_NAME) add_executable(${TARGET_NAME} ${ARGN}) @@ -24,6 +28,7 @@ function(ecal_add_app_console TARGET_NAME) VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} OUTPUT_NAME ecal_${TARGET_NAME}) + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() # This helper function automatically adds a gtest to ecal. @@ -50,6 +55,7 @@ function(ecal_add_gtest TARGET_NAME) VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} OUTPUT_NAME ecal_${TARGET_NAME}) + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_app_gui TARGET_NAME) @@ -59,6 +65,7 @@ function(ecal_add_app_gui TARGET_NAME) VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} OUTPUT_NAME ecal_${TARGET_NAME}) + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_app_qt TARGET_NAME) @@ -70,6 +77,7 @@ function(ecal_add_app_qt TARGET_NAME) if(WIN32) set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup") endif() + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_mon_plugin TARGET_NAME) @@ -94,7 +102,7 @@ function(ecal_add_mon_plugin TARGET_NAME) $<$:QT_NO_DEBUG> $<$:QT_NO_DEBUG> ) - + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_rec_addon TARGET_NAME) @@ -105,7 +113,7 @@ function(ecal_add_rec_addon TARGET_NAME) OUTPUT_NAME ecal_${TARGET_NAME} RUNTIME_OUTPUT_DIRECTORY $,${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/ecalrec_addons,${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/ecal/addons/rec> ) - + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_time_plugin TARGET_NAME) @@ -114,34 +122,7 @@ function(ecal_add_time_plugin TARGET_NAME) VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} ) -endfunction() - -# this appends the 64 / 32 suffix (required for the eCAL Core libraries) -function(ecal_add_ecal_shared_library TARGET_NAME) - add_library(${TARGET_NAME} SHARED ${ARGN}) - set_target_properties(${TARGET_NAME} PROPERTIES - VERSION ${eCAL_VERSION_STRING} - SOVERSION ${eCAL_VERSION_MAJOR} - OUTPUT_NAME ecal_${TARGET_NAME}) -endfunction() - -# this appends the 64 / 32 suffix (required for the eCAL Core libraries) -function(ecal_add_ecal_static_library TARGET_NAME) - add_library(${TARGET_NAME} STATIC ${ARGN}) - set_target_properties(${TARGET_NAME} PROPERTIES - VERSION ${eCAL_VERSION_STRING} - SOVERSION ${eCAL_VERSION_MAJOR} - OUTPUT_NAME ecal_${TARGET_NAME} - POSITION_INDEPENDENT_CODE ON) -endfunction() - -# this appends the 64 / 32 suffix (required for the eCAL Core libraries) -function(ecal_add_ecal_library TARGET_NAME) - if(BUILD_SHARED_LIBS) - ecal_add_ecal_shared_library(${TARGET_NAME} ${ARGN}) - else() - ecal_add_ecal_static_library(${TARGET_NAME} ${ARGN}) - endif() + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_shared_library TARGET_NAME) @@ -150,15 +131,18 @@ function(ecal_add_shared_library TARGET_NAME) VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} OUTPUT_NAME ecal_${TARGET_NAME}) + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_static_library TARGET_NAME) add_library(${TARGET_NAME} STATIC ${ARGN}) - set_property(TARGET ${TARGET_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) set_target_properties(${TARGET_NAME} PROPERTIES VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} - OUTPUT_NAME ecal_${TARGET_NAME}) + OUTPUT_NAME ecal_${TARGET_NAME} + POSITION_INDEPENDENT_CODE ON + ) + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() function(ecal_add_interface_library TARGET_NAME) @@ -179,5 +163,6 @@ function(ecal_add_sample TARGET_NAME) VERSION ${eCAL_VERSION_STRING} SOVERSION ${eCAL_VERSION_MAJOR} OUTPUT_NAME ecal_sample_${TARGET_NAME}) + ecal_add_compiler_warnings(${TARGET_NAME}) endfunction() diff --git a/cmake/helper_functions/ecal_compiler_warnings.cmake b/cmake/helper_functions/ecal_compiler_warnings.cmake new file mode 100644 index 0000000000..dc657e3e0c --- /dev/null +++ b/cmake/helper_functions/ecal_compiler_warnings.cmake @@ -0,0 +1,27 @@ +include_guard(GLOBAL) + +add_library(_ecal_warnings INTERFACE) + +set(cxx_compiler_flags "") + +if("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") + message(STATUS "MSVC detected - Adding flags") + set(cxx_compiler_flags "/MP" "/W4") +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang") + message(STATUS "Setting GNU/Clang flags") + set(cxx_compiler_flags "-Wall" "-Wextra") +else() + message(WARNING "Unknown compiler, will not set warning flags") +endif() + +target_compile_options(_ecal_warnings INTERFACE + "$<$:${cxx_compiler_flags}>" +) + +unset(cxx_compiler_flags) + +function(ecal_add_compiler_warnings TARGET_NAME) + target_link_libraries("${TARGET_NAME}" PRIVATE + "$" + ) +endfunction() diff --git a/cmake/helper_functions/ecal_helper_functions.cmake b/cmake/helper_functions/ecal_helper_functions.cmake index aad8ee8985..66fcb4835c 100644 --- a/cmake/helper_functions/ecal_helper_functions.cmake +++ b/cmake/helper_functions/ecal_helper_functions.cmake @@ -47,3 +47,23 @@ function(ecal_set_subsystem_console TARGET_NAME) LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") endif() endfunction() + + +macro(ecal_disable_all_warnings) + if(MSVC) + message(STATUS "supress thirdparty warnings for windows platform ..") + set(CMAKE_CXX_FLAGS_OLD "${CMAKE_CXX_FLAGS}") + if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") + string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W0") + endif() + endif() +endmacro() + +macro(ecal_restore_warning_level) + if(MSVC) + message(STATUS "reset thirdparty warnings for windows platform ..") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_OLD}") + endif() +endmacro() \ No newline at end of file diff --git a/cmake/helper_functions/ecal_install_functions.cmake b/cmake/helper_functions/ecal_install_functions.cmake index 35dfc8610f..c56c07cb41 100644 --- a/cmake/helper_functions/ecal_install_functions.cmake +++ b/cmake/helper_functions/ecal_install_functions.cmake @@ -21,40 +21,6 @@ # Each target will have to install it by themselves (e.g. install(DIRECTORY ...)) ###################### -# this appends the 64 / 32 suffix (required for the eCAL Core libraries) -function(ecal_install_ecal_library TARGET_NAME) - if(BUILD_SHARED_LIBS) - ecal_install_ecal_shared_library(${TARGET_NAME}) - else() - ecal_install_ecal_static_library(${TARGET_NAME}) - endif() -endfunction() - -# this appends the 64 / 32 suffix (required for the eCAL Core libraries) -function(ecal_install_ecal_static_library TARGET_NAME) - - install(TARGETS ${TARGET_NAME} - # IMPORTANT: Add the library to the "export-set" - EXPORT eCALCoreTargets - ARCHIVE DESTINATION "${eCAL_install_archive_dir}" COMPONENT sdk - LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk - ) -endfunction() - -# installing shared libraries is a li -# this appends the 64 / 32 suffix (required for the eCAL Core libraries) -function(ecal_install_ecal_shared_library TARGET_NAME) - -# Windows, RUNTIME -> .dll, ARCHIVE -> .lib, Unix: LIBRARY -> .so - install(TARGETS ${TARGET_NAME} - # IMPORTANT: Add the library to the "export-set" - EXPORT eCALCoreTargets - RUNTIME DESTINATION "${eCAL_install_bin_dir}" COMPONENT runtime - LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk - ARCHIVE DESTINATION "${eCAL_install_archive_dyn_dir}" COMPONENT sdk - ) -endfunction() - function(ecal_install_library TARGET_NAME) if(BUILD_SHARED_LIBS) ecal_install_shared_library(${TARGET_NAME}) @@ -70,6 +36,7 @@ function(ecal_install_static_library TARGET_NAME) ARCHIVE DESTINATION "${eCAL_install_archive_dir}" COMPONENT sdk LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk ) + ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_bin_dir}" COMPONENT runtime) endfunction() # installing shared libraries is a li @@ -82,6 +49,7 @@ function(ecal_install_shared_library TARGET_NAME) LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk ARCHIVE DESTINATION "${eCAL_install_archive_dyn_dir}" COMPONENT sdk ) + ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_bin_dir}" COMPONENT runtime) endfunction() # These are libraries used by application (e.g. on Unix) @@ -92,6 +60,7 @@ function(ecal_install_private_shared_library TARGET_NAME) RUNTIME DESTINATION "${eCAL_install_bin_dir}" COMPONENT runtime # applies to windows .dll LIBRARY DESTINATION "${eCAL_install_lib_dir}" COMPONENT sdk # applies to unix .so ) + ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_bin_dir}" COMPONENT runtime) endfunction() # Applications are all APPS that come with the eCAL Installation @@ -121,12 +90,14 @@ function(ecal_install_app TARGET_NAME) INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/appmenu/ecal_${TARGET_NAME}.desktop" DESTINATION "${CMAKE_INSTALL_DATADIR}/applications/") endif() +ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_app_dir}" COMPONENT app) endfunction() function(ecal_install_gtest TARGET_NAME) install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION "${eCAL_install_tests_dir}" COMPONENT testing ) +ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_tests_dir}" COMPONENT testing) endfunction() @@ -136,6 +107,7 @@ function(ecal_install_sample TARGET_NAME) install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION "${eCAL_install_samples_dir}" COMPONENT samples ) +ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_samples_dir}" COMPONENT samples) endfunction() # Use this function to install time plugins @@ -145,6 +117,7 @@ install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION "${eCAL_install_bin_dir}/${ECAL_TIME_PLUGIN_DIR}" COMPONENT app LIBRARY DESTINATION "${eCAL_install_lib_dir}/${ECAL_TIME_PLUGIN_DIR}" COMPONENT app ) +ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_bin_dir}/${ECAL_TIME_PLUGIN_DIR}" COMPONENT app) endfunction() # Use this function to install monitor plugins @@ -155,4 +128,21 @@ install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION "${eCAL_install_bin_dir}/${ECAL_MON_PLUGIN_DIR}" COMPONENT app LIBRARY DESTINATION $,${eCAL_install_bin_dir}/${ECAL_MON_PLUGIN_DIR},${eCAL_install_lib_dir}/${ECAL_MON_PLUGIN_DIR}> COMPONENT app ) +ecal_install_pdbs(TARGET ${TARGET_NAME} DESTINATION "${eCAL_install_bin_dir}/${ECAL_MON_PLUGIN_DIR}" COMPONENT app) +endfunction() + +function(ecal_install_pdbs) +if (MSVC) + set(options ) + set(oneValueArgs TARGET DESTINATION COMPONENT) + set(multiValueArgs ) + cmake_parse_arguments(INPUT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + get_target_property(TARGET_TYPE ${INPUT_TARGET} TYPE) + if((${TARGET_TYPE} STREQUAL "SHARED_LIBRARY") OR (${TARGET_TYPE} STREQUAL "EXECUTABLE") OR (${TARGET_TYPE} STREQUAL "MODULE_LIBRARY")) + install(FILES $ DESTINATION ${INPUT_DESTINATION} COMPONENT ${INPUT_COMPONENT} OPTIONAL) + elseif (${TARGET_TYPE} STREQUAL "STATIC_LIBRARY") + # do nothing for static libraries, as it's not supported by CMake. + endif() +endif() endfunction() diff --git a/cmake/helper_functions/ecal_python_functions.cmake b/cmake/helper_functions/ecal_python_functions.cmake deleted file mode 100644 index b51b5b179f..0000000000 --- a/cmake/helper_functions/ecal_python_functions.cmake +++ /dev/null @@ -1,112 +0,0 @@ -# ========================= eCAL LICENSE ================================= -# -# Copyright (C) 2016 - 2019 Continental Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ========================= eCAL LICENSE ================================= - -set(PYTHON_BINARY_DIR ${CMAKE_BINARY_DIR}/python) -set(PYTHON_BINARY_MODULE_DIR ${CMAKE_BINARY_DIR}/python/ecal) - -#! ecal_add_python_module : this function adds a python module -# -# This function -# -# \arg:TARGET_NAME the first argument -# \param:SOURCES SOURCES specify the fooness of the function -# \param:PYTHON_CODE PYTHON_CODE should always be 42 -# \group:GROUP1 GROUP1 is a list of project to foo -# -function(ecal_add_python_module TARGET_NAME) - - set(multiValueArgs SOURCES) - set(singleValueArgs PYTHON_CODE) - cmake_parse_arguments(ARGUMENTS - "" - "${singleValueArgs}" - "${multiValueArgs}" ${ARGN} ) - - if(NOT ARGUMENTS_SOURCES AND NOT ARGUMENTS_PYTHON_CODE) - message(ERROR "Error in ecal_add_python_module: Please specify SOURCES and / or PYTHON_CODE arguments") - endif() - - - # if Sources are specified, a library is created - if(ARGUMENTS_SOURCES) - Python_add_library(${TARGET_NAME} MODULE ${ARGUMENTS_SOURCES}) - set_target_properties(${TARGET_NAME} - PROPERTIES - PREFIX "" - LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PYTHON_BINARY_MODULE_DIR}" - LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PYTHON_BINARY_MODULE_DIR}" - LIBRARY_OUTPUT_DIRECTORY "${PYTHON_BINARY_MODULE_DIR}" - DEBUG_POSTFIX "_d" - ) - # if no sources are specified, then a custom target needs to be created - else() - add_custom_target(${TARGET_NAME} ALL - COMMENT "Custom python target: ${TARGET_NAME}") - endif() - - if(ARGUMENTS_PYTHON_CODE) - # Copy all files from the source folder to the python binary directory. - get_filename_component(absolute_folder_python_files ${ARGUMENTS_PYTHON_CODE} ABSOLUTE) - file(GLOB_RECURSE relative_python_files - RELATIVE ${absolute_folder_python_files} - LIST_DIRECTORIES false - CONFIGURE_DEPENDS - ${absolute_folder_python_files}/*.py) - - foreach (f ${relative_python_files}) - set(origin_file ${absolute_folder_python_files}/${f}) - set(destination_file ${PYTHON_BINARY_MODULE_DIR}/${f}) - configure_file(${origin_file} ${destination_file} COPYONLY) - endforeach() - endif() -endfunction() - -function(ecal_add_pybind11_module TARGET_NAME) - set(multiValueArgs SOURCES) - set(singleValueArgs PYTHON_CODE) - cmake_parse_arguments(ARGUMENTS - "" - "${singleValueArgs}" - "${multiValueArgs}" ${ARGN} ) - - if(NOT ARGUMENTS_SOURCES AND NOT ARGUMENTS_PYTHON_CODE) - message(ERROR "Error in ecal_add_python_module: Please specify SOURCES and / or PYTHON_CODE arguments") - endif() - - - pybind11_add_module(${TARGET_NAME} ${ARGUMENTS_SOURCES}) - set_target_properties(${TARGET_NAME} - PROPERTIES - PREFIX "" - LIBRARY_OUTPUT_DIRECTORY_DEBUG "${PYTHON_BINARY_MODULE_DIR}" - LIBRARY_OUTPUT_DIRECTORY_RELEASE "${PYTHON_BINARY_MODULE_DIR}" - LIBRARY_OUTPUT_DIRECTORY "${PYTHON_BINARY_MODULE_DIR}" - DEBUG_POSTFIX "_d" - ) - - if(ARGUMENTS_PYTHON_CODE) - add_custom_command( - TARGET ${TARGET_NAME} - PRE_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory ${ARGUMENTS_PYTHON_CODE} ${PYTHON_BINARY_MODULE_DIR} - ) - endif() -endfunction () - -function(ecal_install_python_module) -endfunction() \ No newline at end of file diff --git a/thirdparty/cmakefunctions/cmake_functions/qt/qt_msvc_path.cmake b/cmake/qt_msvc_path.cmake similarity index 89% rename from thirdparty/cmakefunctions/cmake_functions/qt/qt_msvc_path.cmake rename to cmake/qt_msvc_path.cmake index 3d3db952ad..3a17d95c0f 100644 --- a/thirdparty/cmakefunctions/cmake_functions/qt/qt_msvc_path.cmake +++ b/cmake/qt_msvc_path.cmake @@ -112,8 +112,17 @@ macro(autodetect_qt_msvc_dir) endif() message(STATUS "Using Qt ${BEST_QT_MAJOR}.${BEST_QT_MINOR}.${BEST_QT_PATCH} MSVC ${BEST_QT_MSVC_YEAR} from ${BEST_QT_DIRECTORY}") - SET(Qt${BEST_QT_MAJOR}_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}/") - SET(Qt${BEST_QT_MAJOR}Test_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}Test") + + list(APPEND CMAKE_PREFIX_PATH "${BEST_QT_DIRECTORY}") + # Dirs for legacy targets with version: + + #SET(Qt${BEST_QT_MAJOR}_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}/") + #SET(Qt${BEST_QT_MAJOR}CoreTools_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}CoreTools/") + #SET(Qt${BEST_QT_MAJOR}Test_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}Test") + + # Dirs for modern version-less targets + #SET(QT_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}/") + #SET(QTTest_DIR "${BEST_QT_DIRECTORY}/lib/cmake/Qt${BEST_QT_MAJOR}Test") endif() endmacro() diff --git a/cmake/submodule_dependencies.cmake b/cmake/submodule_dependencies.cmake new file mode 100644 index 0000000000..a0a6726db4 --- /dev/null +++ b/cmake/submodule_dependencies.cmake @@ -0,0 +1,73 @@ +# Always ensure we have the policy settings this provider expects +cmake_minimum_required(VERSION 3.24) + +set(ecal_submodule_dependency_provider_root_dir ${CMAKE_CURRENT_LIST_DIR}) + +set(ecal_submodule_dependencies + asio + CMakeFunctions + CURL + ecaludp + fineftp + ftxui + GTest + HDF5 + #libssh2 + Protobuf + qwt + recycle + spdlog + tclap + tcp_pubsub + termcolor + tinyxml2 + udpcap + yaml-cpp +) + +set(ecal_inproject_dependencies + eCAL +) + +macro(ecal_handle_submodule_dependency package_name) + string(TOUPPER ${package_name} package_name_upper) + string(TOLOWER ${package_name} package_name_lower) + + option(ECAL_THIRDPARTY_BUILD_${package_name_upper} "Build ${package_name} with eCAL" ON) + + if (ECAL_THIRDPARTY_BUILD_${package_name_upper}) + include(${ecal_submodule_dependency_provider_root_dir}/../thirdparty/${package_name_lower}/build-${package_name_lower}.cmake) + set(${package_name}_FOUND TRUE) + else () + find_package(${package_name} BYPASS_PROVIDER ${ARGN}) + endif () +endmacro() + +macro(ecal_handle_inproject_dependency package_name) + set(${package_name}_FOUND TRUE) +endmacro() + +macro(ecal_handle_other_dependency package_name) + find_package(${package_name} BYPASS_PROVIDER ${ARGN}) +endmacro() + +macro(ecal_dependencies_provider method package_name) + list(FIND ecal_submodule_dependencies ${package_name} is_submodule_dependency) + list(FIND ecal_inproject_dependencies ${package_name} is_inproject_dependency) + + #inproject dependency + if (NOT ${is_submodule_dependency} EQUAL -1) + ecal_handle_submodule_dependency(${package_name} ${ARGN}) + #submodule dependency + elseif (NOT ${is_inproject_dependency} EQUAL -1) + ecal_handle_inproject_dependency(${package_name} ${ARGN}) + else () + #other dependency + ecal_handle_other_dependency(${package_name} ${ARGN}) + endif () +endmacro() + +cmake_language( + SET_DEPENDENCY_PROVIDER ecal_dependencies_provider + SUPPORTED_METHODS FIND_PACKAGE +) \ No newline at end of file diff --git a/contrib/ecalhdf5/CMakeLists.txt b/contrib/ecalhdf5/CMakeLists.txt index d5285101c1..37b87df48f 100644 --- a/contrib/ecalhdf5/CMakeLists.txt +++ b/contrib/ecalhdf5/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2024 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,7 +29,10 @@ else() endif() set(ecalhdf5_src - src/eh5_meas.cpp + src/datatype_helper.cpp + src/datatype_helper.h + src/eh5_meas_api_v2.cpp + src/eh5_meas_api_v3.cpp src/eh5_meas_dir.cpp src/eh5_meas_dir.h src/eh5_meas_file_v1.cpp @@ -42,9 +45,15 @@ set(ecalhdf5_src src/eh5_meas_file_v4.h src/eh5_meas_file_v5.cpp src/eh5_meas_file_v5.h + src/eh5_meas_file_v6.cpp + src/eh5_meas_file_v6.h src/eh5_meas_file_writer_v5.cpp src/eh5_meas_file_writer_v5.h + src/eh5_meas_file_writer_v6.cpp + src/eh5_meas_file_writer_v6.h src/eh5_meas_impl.h + src/hdf5_helper.h + src/hdf5_helper.cpp src/escape.cpp src/escape.h ) @@ -52,6 +61,8 @@ set(ecalhdf5_src set(ecalhdf5_header_base include/ecalhdf5/eh5_defs.h include/ecalhdf5/eh5_meas.h + include/ecalhdf5/eh5_meas_api_v2.h + include/ecalhdf5/eh5_meas_api_v3.h include/ecalhdf5/eh5_types.h ) @@ -67,7 +78,10 @@ target_include_directories(${PROJECT_NAME} target_compile_definitions(${PROJECT_NAME} PRIVATE - $<$:_UNICODE>) + $<$:_UNICODE> + PUBLIC + ECAL_EH5_API_VERSION=2 + ) target_compile_options(${PROJECT_NAME} PRIVATE diff --git a/contrib/ecalhdf5/include/ecalhdf5/eh5_defs.h b/contrib/ecalhdf5/include/ecalhdf5/eh5_defs.h index 3208ffc1fe..a05f6c027b 100644 --- a/contrib/ecalhdf5/include/ecalhdf5/eh5_defs.h +++ b/contrib/ecalhdf5/include/ecalhdf5/eh5_defs.h @@ -1,6 +1,6 @@ ;/* ========================= eCAL LICENSE ================================= ; * -; * Copyright (C) 2016 - 2019 Continental Corporation +; * Copyright (C) 2016 - 2024 Continental Corporation ; * ; * Licensed under the Apache License, Version 2.0 (the "License"); ; * you may not use this file except in compliance with the License. @@ -25,13 +25,13 @@ #pragma once ;/* version parsed out into numeric values */ -#define ECAL_HDF5_VERSION_MAJOR 2 //!< eCAL HDF5 major version -#define ECAL_HDF5_VERSION_MINOR 1 //!< eCAL HDF5 minor version +#define ECAL_HDF5_VERSION_MAJOR 3 //!< eCAL HDF5 major version +#define ECAL_HDF5_VERSION_MINOR 0 //!< eCAL HDF5 minor version #define ECAL_HDF5_VERSION_PATCH 0 //!< eCAL HDF5 patch version ;/* version as string */ -#define ECAL_HDF5_VERSION "v.2.1.0.20180329" //!< eCAL HDF5 version string -#define ECAL_HDF5_DATE "29.03.2018" //!< eCAL HDF5 version date +#define ECAL_HDF5_VERSION "v.3.0.0.20241203" //!< eCAL HDF5 version string +#define ECAL_HDF5_DATE "03.12.2024" //!< eCAL HDF5 version date ;/* name as string */ #define ECAL_HDF5_NAME "eCALHDF5" //!< eCAL HDF5 library name diff --git a/contrib/ecalhdf5/include/ecalhdf5/eh5_meas.h b/contrib/ecalhdf5/include/ecalhdf5/eh5_meas.h index 848f640c0a..13e0771166 100644 --- a/contrib/ecalhdf5/include/ecalhdf5/eh5_meas.h +++ b/contrib/ecalhdf5/include/ecalhdf5/eh5_meas.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ #pragma once +#include #include #include #include @@ -31,292 +32,11 @@ #include "eh5_types.h" -namespace eCAL -{ - namespace eh5 - { - class HDF5MeasImpl; +#if defined(ECAL_EH5_NO_DEPRECATION_WARNINGS) +#define ECAL_EH5_DEPRECATE(__message__) //!< Don't print deprecation warnigns +#else +#define ECAL_EH5_DEPRECATE(__message__) [[deprecated(__message__)]] //!< Deprecate the following function +#endif - /** - * @brief eCAL HDF5 measurement API - **/ - class HDF5Meas - { - public: - /** - * @brief Constructor - **/ - HDF5Meas(); - - /** - * @brief Constructor - * - * @param path Input file path / measurement directory path (see meas directory structure description bellow, in Open method). - * @param access Access type - * - **/ - explicit HDF5Meas(const std::string& path, eAccessType access = RDONLY); - - /** - * @brief Destructor - **/ - ~HDF5Meas(); - - /** - * @brief Copy constructor deleted - **/ - HDF5Meas(const HDF5Meas& other) = delete; - /** - * @brief Move assignemnt deleted - **/ - HDF5Meas& operator=(const HDF5Meas& other) = delete; - - /** - * @brief Move constructor - **/ - HDF5Meas(HDF5Meas&&) = default; - /** - * @brief Move assignment - **/ - HDF5Meas& operator=(HDF5Meas&&) = default; - - /** - * @brief Open file - * - * @param path Input file path / measurement directory path. - * - * Default measurement directory structure: - * - root directory e.g.: M:\measurement_directory\measurement01 - * - documents directory: |_doc - * - hosts directories: |_Host1 (e.g.: CARPC01) - * |_Host2 (e.g.: CARPC02) - * - * File path as input (eAccessType::RDONLY): - * - root directory (e.g.: M:\measurement_directory\measurement01) in this case all hosts subdirectories will be iterated, - * - host directory (e.g.: M:\measurement_directory\measurement01\CARPC01), - * - file path, path to file from measurement (e.g.: M:\measurement_directory\measurement01\CARPC01\meas01_05.hdf5). - * - * File path as output (eAccessType::CREATE): - * - full path to measurement directory (recommended with host name) (e.g.: M:\measurement_directory\measurement01\CARPC01), - * - to set the name of the actual hdf5 file use SetFileBaseName method. - * - * @param access Access type - * - * @return true if output (eAccessType::CREATE) measurement directory structure can be accessed/created, false otherwise. - * true if input (eAccessType::RDONLY) measurement/file path was opened, false otherwise. - **/ - bool Open(const std::string& path, eAccessType access = RDONLY); - - /** - * @brief Close file - * - * @return true if succeeds, false if it fails - **/ - bool Close(); - - /** - * @brief Checks if file/measurement is ok - * - * @return true if meas can be opened(read) or location is accessible(write), false otherwise - **/ - bool IsOk() const; - - /** - * @brief Get the File Type Version of the current opened file - * - * @return file version - **/ - std::string GetFileVersion() const; - - /** - * @brief Gets maximum allowed size for an individual file - * - * @return maximum size in MB - **/ - size_t GetMaxSizePerFile() const; - - /** - * @brief Sets maximum allowed size for an individual file - * - * @param size maximum size in MB - **/ - void SetMaxSizePerFile(size_t size); - - /** - * @brief Whether each Channel shall be writte in its own file - * - * When enabled, data is clustered by channel and each channel is written - * to its own file. The filenames will consist of the basename and the - * channel name. - * - * @return true, if one file per channel is enabled - */ - bool IsOneFilePerChannelEnabled() const; - - /** - * @brief Enable / disable the creation of one individual file per channel - * - * When enabled, data is clustered by channel and each channel is written - * to its own file. The filenames will consist of the basename and the - * channel name. - * - * @param enabled Whether one file shall be created per channel - */ - void SetOneFilePerChannelEnabled(bool enabled); - - /** - * @brief Get the available channel names of the current opened file / measurement - * - * @return channel names - **/ - std::set GetChannelNames() const; - - /** - * @brief Check if channel exists in measurement - * - * @param channel_name name of the channel - * - * @return true if exists, false otherwise - **/ - bool HasChannel(const std::string& channel_name) const; - - /** - * @brief Get the channel description for the given channel - * - * @param channel_name channel name - * - * @return channel description - **/ - std::string GetChannelDescription(const std::string& channel_name) const; - - /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel - **/ - void SetChannelDescription(const std::string& channel_name, const std::string& description); - - /** - * @brief Gets the channel type of the given channel - * - * @param channel_name channel name - * - * @return channel type - **/ - std::string GetChannelType(const std::string& channel_name) const; - - /** - * @brief Set type of the given channel - * - * @param channel_name channel name - * @param type type of the channel - **/ - void SetChannelType(const std::string& channel_name, const std::string& type); - - /** - * @brief Gets minimum timestamp for specified channel - * - * @param channel_name channel name - * - * @return minimum timestamp value - **/ - long long GetMinTimestamp(const std::string& channel_name) const; - - /** - * @brief Gets maximum timestamp for specified channel - * - * @param channel_name channel name - * - * @return maximum timestamp value - **/ - long long GetMaxTimestamp(const std::string& channel_name) const; - - /** - * @brief Gets the header info for all data entries for the given channel - * Header = timestamp + entry id - * - * @param [in] channel_name channel name - * @param [out] entries header info for all data entries - * - * @return true if succeeds, false if it fails - **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const; - - /** - * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) - * Header = timestamp + entry id - * - * @param [in] channel_name channel name - * @param [in] begin time range begin timestamp - * @param [in] end time range end timestamp - * @param [out] entries header info for data entries in given range - * - * @return true if succeeds, false if it fails - **/ - bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const; - - /** - * @brief Gets data size of a specific entry - * - * @param [in] entry_id Entry ID - * @param [out] size Entry data size - * - * @return true if succeeds, false if it fails - **/ - bool GetEntryDataSize(long long entry_id, size_t& size) const; - - /** - * @brief Gets data from a specific entry - * - * @param [in] entry_id Entry ID - * @param [out] data Entry data - * - * @return true if succeeds, false if it fails - **/ - bool GetEntryData(long long entry_id, void* data) const; - - /** - * @brief Set measurement file base name (desired name for the actual hdf5 files that will be created) - * - * @param base_name Name of the hdf5 files that will be created. - **/ - void SetFileBaseName(const std::string& base_name); - - /** - * @brief Add entry to file - * - * @param data data to be added - * @param size size of the data - * @param snd_timestamp send time stamp - * @param rcv_timestamp receive time stamp - * @param channel_name channel name - * @param id message id - * @param clock message clock - * - * @return true if succeeds, false if it fails - **/ - bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock); - - /** - * @brief Callback function type for pre file split notification - **/ - typedef std::function CallbackFunction; - - /** - * @brief Connect callback for pre file split notification - * - * @param cb callback function - **/ - void ConnectPreSplitCallback(CallbackFunction cb); - - /** - * @brief Disconnect pre file split callback - **/ - void DisconnectPreSplitCallback(); - - private: - std::unique_ptr hdf_meas_impl_; - }; - } // namespace eh5 -} // namespace eCAL +#include "eh5_meas_api_v2.h" +#include "eh5_meas_api_v3.h" diff --git a/contrib/ecalhdf5/include/ecalhdf5/eh5_meas_api_v2.h b/contrib/ecalhdf5/include/ecalhdf5/eh5_meas_api_v2.h new file mode 100644 index 0000000000..ccba86ad64 --- /dev/null +++ b/contrib/ecalhdf5/include/ecalhdf5/eh5_meas_api_v2.h @@ -0,0 +1,351 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file eh5_meas.h + * @brief eCALHDF5 measurement class +**/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "eh5_types.h" + +namespace eCAL +{ + namespace eh5 + { + inline namespace v3 + { + class HDF5Meas; + } + + namespace v2 + { + /** + * @brief eCAL HDF5 measurement API + **/ + class HDF5Meas + { + public: + /** + * @brief Constructor + **/ + HDF5Meas(); + + /** + * @brief Constructor + * + * @param path Input file path / measurement directory path (see meas directory structure description bellow, in Open method). + * @param access Access type + * + **/ + explicit HDF5Meas(const std::string& path, eAccessType access = RDONLY); + + /** + * @brief Destructor + **/ + ~HDF5Meas(); + + /** + * @brief Copy constructor deleted + **/ + HDF5Meas(const HDF5Meas& other) = delete; + /** + * @brief Move assignemnt deleted + **/ + HDF5Meas& operator=(const HDF5Meas& other) = delete; + + /** + * @brief Move constructor + **/ + HDF5Meas(HDF5Meas&&) = default; + /** + * @brief Move assignment + **/ + HDF5Meas& operator=(HDF5Meas&&) = default; + + /** + * @brief Open file + * + * @param path Input file path / measurement directory path. + * + * Default measurement directory structure: + * - root directory e.g.: M:\measurement_directory\measurement01 + * - documents directory: |_doc + * - hosts directories: |_Host1 (e.g.: CARPC01) + * |_Host2 (e.g.: CARPC02) + * + * File path as input (eAccessType::RDONLY): + * - root directory (e.g.: M:\measurement_directory\measurement01) in this case all hosts subdirectories will be iterated, + * - host directory (e.g.: M:\measurement_directory\measurement01\CARPC01), + * - file path, path to file from measurement (e.g.: M:\measurement_directory\measurement01\CARPC01\meas01_05.hdf5). + * + * File path as output (eAccessType::CREATE): + * - full path to measurement directory (recommended with host name) (e.g.: M:\measurement_directory\measurement01\CARPC01), + * - to set the name of the actual hdf5 file use SetFileBaseName method. + * + * @param access Access type + * + * @return true if output (eAccessType::CREATE) measurement directory structure can be accessed/created, false otherwise. + * true if input (eAccessType::RDONLY) measurement/file path was opened, false otherwise. + **/ + bool Open(const std::string& path, eAccessType access = RDONLY); + + /** + * @brief Close file + * + * @return true if succeeds, false if it fails + **/ + bool Close(); + + /** + * @brief Checks if file/measurement is ok + * + * @return true if meas can be opened(read) or location is accessible(write), false otherwise + **/ + bool IsOk() const; + + /** + * @brief Get the File Type Version of the current opened file + * + * @return file version + **/ + std::string GetFileVersion() const; + + /** + * @brief Gets maximum allowed size for an individual file + * + * @return maximum size in MB + **/ + size_t GetMaxSizePerFile() const; + + /** + * @brief Sets maximum allowed size for an individual file + * + * @param size maximum size in MB + **/ + void SetMaxSizePerFile(size_t size); + + /** + * @brief Whether each Channel shall be writte in its own file + * + * When enabled, data is clustered by channel and each channel is written + * to its own file. The filenames will consist of the basename and the + * channel name. + * + * @return true, if one file per channel is enabled + */ + bool IsOneFilePerChannelEnabled() const; + + /** + * @brief Enable / disable the creation of one individual file per channel + * + * When enabled, data is clustered by channel and each channel is written + * to its own file. The filenames will consist of the basename and the + * channel name. + * + * @param enabled Whether one file shall be created per channel + */ + void SetOneFilePerChannelEnabled(bool enabled); + + /** + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names + **/ + std::set GetChannelNames() const; + + /** + * @brief Check if channel exists in measurement + * + * @param channel_name name of the channel + * + * @return true if exists, false otherwise + **/ + bool HasChannel(const std::string& channel_name) const; + + /** + * @brief Get the channel description for the given channel + * + * @param channel_name channel name + * + * @return channel description + **/ + std::string GetChannelDescription(const std::string& channel_name) const; + + /** + * @brief Set description of the given channel + * + * @param channel_name channel name + * @param description description of the channel + **/ + void SetChannelDescription(const std::string& channel_name, const std::string& description); + + /** + * @brief Gets the channel type of the given channel + * + * @param channel_name channel name + * + * @return channel type + **/ + std::string GetChannelType(const std::string& channel_name) const; + + /** + * @brief Set type of the given channel + * + * @param channel_name channel name + * @param type type of the channel + **/ + void SetChannelType(const std::string& channel_name, const std::string& type); + + /** + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type + **/ + DataTypeInformation GetChannelDataTypeInformation(const std::string& channel_name) const; + + /** + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type + **/ + void SetChannelDataTypeInformation(const std::string& channel_name, const DataTypeInformation& info); + + /** + * @brief Gets minimum timestamp for specified channel + * + * @param channel_name channel name + * + * @return minimum timestamp value + **/ + long long GetMinTimestamp(const std::string& channel_name) const; + + /** + * @brief Gets maximum timestamp for specified channel + * + * @param channel_name channel name + * + * @return maximum timestamp value + **/ + long long GetMaxTimestamp(const std::string& channel_name) const; + + /** + * @brief Gets the header info for all data entries for the given channel + * Header = timestamp + entry id + * + * @param [in] channel_name channel name + * @param [out] entries header info for all data entries + * + * @return true if succeeds, false if it fails + **/ + bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const; + + /** + * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) + * Header = timestamp + entry id + * + * @param [in] channel_name channel name + * @param [in] begin time range begin timestamp + * @param [in] end time range end timestamp + * @param [out] entries header info for data entries in given range + * + * @return true if succeeds, false if it fails + **/ + bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const; + + /** + * @brief Gets data size of a specific entry + * + * @param [in] entry_id Entry ID + * @param [out] size Entry data size + * + * @return true if succeeds, false if it fails + **/ + bool GetEntryDataSize(long long entry_id, size_t& size) const; + + /** + * @brief Gets data from a specific entry + * + * @param [in] entry_id Entry ID + * @param [out] data Entry data + * + * @return true if succeeds, false if it fails + **/ + bool GetEntryData(long long entry_id, void* data) const; + + /** + * @brief Set measurement file base name (desired name for the actual hdf5 files that will be created) + * + * @param base_name Name of the hdf5 files that will be created. + **/ + void SetFileBaseName(const std::string& base_name); + + /** + * @brief Add entry to file + * + * @param data data to be added + * @param size size of the data + * @param snd_timestamp send time stamp + * @param rcv_timestamp receive time stamp + * @param channel_name channel name + * @param id message id + * @param clock message clock + * + * @return true if succeeds, false if it fails + **/ + bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock); + + /** + * @brief Callback function type for pre file split notification + **/ + typedef std::function CallbackFunction; + + /** + * @brief Connect callback for pre file split notification + * + * @param cb callback function + **/ + void ConnectPreSplitCallback(CallbackFunction cb); + + /** + * @brief Disconnect pre file split callback + **/ + void DisconnectPreSplitCallback(); + + private: + std::unique_ptr hdf_meas_impl_; + // this map saves all datatype infos that have been set, so that the api can still + // support setting type and descriptor separately + std::map data_type_info_map; + }; + } // namespace v1 + } // namespace eh5 +} // namespace eCAL diff --git a/contrib/ecalhdf5/include/ecalhdf5/eh5_meas_api_v3.h b/contrib/ecalhdf5/include/ecalhdf5/eh5_meas_api_v3.h new file mode 100644 index 0000000000..80ec6a6ee0 --- /dev/null +++ b/contrib/ecalhdf5/include/ecalhdf5/eh5_meas_api_v3.h @@ -0,0 +1,312 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file eh5_meas.h + * @brief eCALHDF5 measurement class +**/ + +#pragma once + +#include +#include +#include +#include +#include + +#include "eh5_types.h" + + +namespace eCAL +{ + namespace eh5 + { + class HDF5MeasImpl; + + inline namespace v3{ + + /** + * @brief eCAL HDF5 measurement API + **/ + class HDF5Meas + { + public: + /** + * @brief Constructor + **/ + HDF5Meas(); + + /** + * @brief Constructor + * + * @param path Input file path / measurement directory path (see meas directory structure description bellow, in Open method). + * @param access Access type + * + **/ + explicit HDF5Meas(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); + + /** + * @brief Destructor + **/ + ~HDF5Meas(); + + /** + * @brief Copy constructor deleted + **/ + HDF5Meas(const HDF5Meas& other) = delete; + /** + * @brief Move assignemnt deleted + **/ + HDF5Meas& operator=(const HDF5Meas& other) = delete; + + /** + * @brief Move constructor + **/ + HDF5Meas(HDF5Meas&&) = default; + /** + * @brief Move assignment + **/ + HDF5Meas& operator=(HDF5Meas&&) = default; + + /** + * @brief Open file + * + * @param path Input file path / measurement directory path. + * + * Default measurement directory structure: + * - root directory e.g.: M:\measurement_directory\measurement01 + * - documents directory: |_doc + * - hosts directories: |_Host1 (e.g.: CARPC01) + * |_Host2 (e.g.: CARPC02) + * + * File path as input (eAccessType::RDONLY): + * - root directory (e.g.: M:\measurement_directory\measurement01) in this case all hosts subdirectories will be iterated, + * - host directory (e.g.: M:\measurement_directory\measurement01\CARPC01), + * - file path, path to file from measurement (e.g.: M:\measurement_directory\measurement01\CARPC01\meas01_05.hdf5). + * + * File path as output (eAccessType::CREATE): + * - full path to measurement directory (recommended with host name) (e.g.: M:\measurement_directory\measurement01\CARPC01), + * - to set the name of the actual hdf5 file use SetFileBaseName method. + * + * @param access Access type + * + * @return true if output (eAccessType::CREATE) measurement directory structure can be accessed/created, false otherwise. + * true if input (eAccessType::RDONLY) measurement/file path was opened, false otherwise. + **/ + bool Open(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); + + /** + * @brief Close file + * + * @return true if succeeds, false if it fails + **/ + bool Close(); + + /** + * @brief Checks if file/measurement is ok + * + * @return true if meas can be opened(read) or location is accessible(write), false otherwise + **/ + bool IsOk() const; + + /** + * @brief Get the File Type Version of the current opened file + * + * @return file version + **/ + std::string GetFileVersion() const; + + /** + * @brief Gets maximum allowed size for an individual file + * + * @return maximum size in MB + **/ + size_t GetMaxSizePerFile() const; + + /** + * @brief Sets maximum allowed size for an individual file + * + * @param size maximum size in MB + **/ + void SetMaxSizePerFile(size_t size); + + /** + * @brief Whether each Channel shall be writte in its own file + * + * When enabled, data is clustered by channel and each channel is written + * to its own file. The filenames will consist of the basename and the + * channel name. + * + * @return true, if one file per channel is enabled + */ + bool IsOneFilePerChannelEnabled() const; + + /** + * @brief Enable / disable the creation of one individual file per channel + * + * When enabled, data is clustered by channel and each channel is written + * to its own file. The filenames will consist of the basename and the + * channel name. + * + * @param enabled Whether one file shall be created per channel + */ + void SetOneFilePerChannelEnabled(bool enabled); + + /** + * @brief Get the available channel names of the current opened file / measurement + * + * @return Channels (channel name & id) + **/ + std::set GetChannels() const; + + /** + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise + **/ + bool HasChannel(const eCAL::eh5::SChannel& channel) const; + + /** + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type + **/ + DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const; + + /** + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type + **/ + void SetChannelDataTypeInformation(const SChannel& channel, const DataTypeInformation& info); + + /** + * @brief Gets minimum timestamp for specified channel + * + * @param channel channel (name & id) + * + * @return minimum timestamp value + **/ + long long GetMinTimestamp(const SChannel& channel) const; + + /** + * @brief Gets maximum timestamp for specified channel + * + * @param channel channel (name & id) + * + * @return maximum timestamp value + **/ + long long GetMaxTimestamp(const SChannel& channel) const; + + /** + * @brief Gets the header info for all data entries for the given channel + * Header = timestamp + entry id + * + * @param [in] channel channel (name & id) + * @param [out] entries header info for all data entries + * + * @return true if succeeds, false if it fails + **/ + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const; + + /** + * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) + * Header = timestamp + entry id + * + * @param [in] channel channel (name & id) + * @param [in] begin time range begin timestamp + * @param [in] end time range end timestamp + * @param [out] entries header info for data entries in given range + * + * @return true if succeeds, false if it fails + **/ + bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const; + + /** + * @brief Gets data size of a specific entry + * + * @param [in] entry_id Entry ID + * @param [out] size Entry data size + * + * @return true if succeeds, false if it fails + **/ + bool GetEntryDataSize(long long entry_id, size_t& size) const; + + /** + * @brief Gets data from a specific entry + * + * @param [in] entry_id Entry ID + * @param [out] data Entry data + * + * @return true if succeeds, false if it fails + **/ + bool GetEntryData(long long entry_id, void* data) const; + + /** + * @brief Set measurement file base name (desired name for the actual hdf5 files that will be created) + * + * @param base_name Name of the hdf5 files that will be created. + **/ + void SetFileBaseName(const std::string& base_name); + + /** + * @brief Add entry to file + * + * @param data data to be added + * @param size size of the data + * @param snd_timestamp send time stamp + * @param rcv_timestamp receive time stamp + * @param channel channel channel (name & id) + * @param id message id + * @param clock message clock + * + * @return true if succeeds, false if it fails + **/ + bool AddEntryToFile(const SWriteEntry& entry); + + /** + * @brief Callback function type for pre file split notification + **/ + typedef std::function CallbackFunction; + + /** + * @brief Connect callback for pre file split notification + * + * @param cb callback function + **/ + void ConnectPreSplitCallback(CallbackFunction cb); + + /** + * @brief Disconnect pre file split callback + **/ + void DisconnectPreSplitCallback(); + + private: + std::unique_ptr hdf_meas_impl_; + }; + } + } // namespace eh5 +} // namespace eCAL diff --git a/contrib/ecalhdf5/include/ecalhdf5/eh5_types.h b/contrib/ecalhdf5/include/ecalhdf5/eh5_types.h index 18332bb5fb..1ec43591fa 100644 --- a/contrib/ecalhdf5/include/ecalhdf5/eh5_types.h +++ b/contrib/ecalhdf5/include/ecalhdf5/eh5_types.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,17 +38,41 @@ namespace eCAL const std::string kChnNameAttribTitle ("Channel Name"); const std::string kChnDescAttrTitle ("Channel Description"); const std::string kChnTypeAttrTitle ("Channel Type"); + const std::string kChnIdTypename ("TypeName"); + const std::string kChnIdEncoding ("TypeEncoding"); + const std::string kChnIdDescriptor ("TypeDescriptor"); + const std::string kChnIdData ("DataTable"); const std::string kFileVerAttrTitle ("Version"); const std::string kTimestampAttrTitle ("Timestamps"); const std::string kChnAttrTitle ("Channels"); // Remove @eCAL6 -> backwards compatibility with old interface! + using SChannel = eCAL::experimental::measurement::base::Channel; using SEntryInfo = eCAL::experimental::measurement::base::EntryInfo; using EntryInfoSet = eCAL::experimental::measurement::base::EntryInfoSet; using EntryInfoVect = eCAL::experimental::measurement::base::EntryInfoVect; - using eAccessType = eCAL::experimental::measurement::base::AccessType; - using eCAL::experimental::measurement::base::RDONLY; - using eCAL::experimental::measurement::base::CREATE; + using SWriteEntry = eCAL::experimental::measurement::base::WriteEntry; + + namespace v2 + { + enum eAccessType + { + RDONLY, //!< ReadOnly - the measurement can only be read + CREATE, //!< Create - a new measurement will be created + }; + } + + inline namespace v3 + { + enum class eAccessType + { + RDONLY, //!< ReadOnly - the measurement can only be read + CREATE, //!< Create - a new measurement will be created + CREATE_V5 //!< Create a legacy V5 hdf5 measurement (For testing purpose only!) + }; + } + + using eCAL::experimental::measurement::base::DataTypeInformation; //!< @endcond } // namespace eh5 } // namespace eCAL diff --git a/contrib/ecalhdf5/src/datatype_helper.cpp b/contrib/ecalhdf5/src/datatype_helper.cpp new file mode 100644 index 0000000000..63d5a8fb0a --- /dev/null +++ b/contrib/ecalhdf5/src/datatype_helper.cpp @@ -0,0 +1,60 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +#include "datatype_helper.h" + +namespace eCAL +{ + namespace eh5 + { + DataTypeInformation CreateInfo(const std::string& combined_topic_type_, const std::string& descriptor_) + { + eCAL::eh5::DataTypeInformation info; + auto pos = combined_topic_type_.find(':'); + if (pos == std::string::npos) + { + info.name = combined_topic_type_; + info.encoding = ""; + } + else + { + info.name = combined_topic_type_.substr(pos + 1); + info.encoding = combined_topic_type_.substr(0, pos); + } + info.descriptor = descriptor_; + return info; + } + + std::pair FromInfo(const eCAL::eh5::DataTypeInformation& datatype_info_) + { + std::string combined_topic_type; + if (datatype_info_.encoding.empty()) + { + combined_topic_type = datatype_info_.name; + } + else + { + combined_topic_type = datatype_info_.encoding + ":" + datatype_info_.name; + } + + return std::make_pair(combined_topic_type, datatype_info_.descriptor); + } + + } +} \ No newline at end of file diff --git a/contrib/ecalhdf5/src/datatype_helper.h b/contrib/ecalhdf5/src/datatype_helper.h new file mode 100644 index 0000000000..cb1a1e3d03 --- /dev/null +++ b/contrib/ecalhdf5/src/datatype_helper.h @@ -0,0 +1,34 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include + + +namespace eCAL +{ + namespace eh5 + { + DataTypeInformation CreateInfo(const std::string& combined_topic_type_, const std::string& descriptor_); + std::pair FromInfo(const DataTypeInformation& datatype_info_); + } +} \ No newline at end of file diff --git a/contrib/ecalhdf5/src/eh5_meas.cpp b/contrib/ecalhdf5/src/eh5_meas.cpp deleted file mode 100644 index ce70758905..0000000000 --- a/contrib/ecalhdf5/src/eh5_meas.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * @brief eCALHDF5 measurement class -**/ - -#include - -#include - -#include - -#include "eh5_meas_dir.h" -#include "eh5_meas_file_v1.h" -#include "eh5_meas_file_v2.h" -#include "eh5_meas_file_v3.h" -#include "eh5_meas_file_v4.h" -#include "eh5_meas_file_v5.h" - -#include "escape.h" - -namespace -{ - const double file_version_max(5.0); -} - -eCAL::eh5::HDF5Meas::HDF5Meas() -= default; - -eCAL::eh5::HDF5Meas::HDF5Meas(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) -{ - Open(path, access); -} - -eCAL::eh5::HDF5Meas::~HDF5Meas() -= default; - -bool eCAL::eh5::HDF5Meas::Open(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) -{ - if (hdf_meas_impl_) - { - Close(); - } - - if (access == eAccessType::CREATE) - { - EcalUtils::Filesystem::MkPath(path, EcalUtils::Filesystem::OsStyle::Current); - } - - auto type = EcalUtils::Filesystem::GetType(path, EcalUtils::Filesystem::OsStyle::Current); - - switch (type) - { - case EcalUtils::Filesystem::Dir: - { - hdf_meas_impl_ = std::make_unique(path, access); - break; - } - case EcalUtils::Filesystem::RegularFile: - { - hdf_meas_impl_ = std::make_unique(path, access); - - if (!hdf_meas_impl_->IsOk()) - { - hdf_meas_impl_.reset(); - return false; - } - - // no file version at all ? - auto file_version = GetFileVersion(); - if (file_version.empty()) - { - hdf_meas_impl_.reset(); - return false; - } - - // future file version ? - auto file_version_numeric = stod(file_version); - if (file_version_numeric > file_version_max) - { - hdf_meas_impl_.reset(); - return false; - } - - // check if we need to create an older file reader - if (file_version_numeric < 1.0 || file_version_numeric > file_version_max) - { - hdf_meas_impl_.reset(); - } - else if (file_version_numeric >= 1.0 && file_version_numeric < 2.0) - { - hdf_meas_impl_ = std::make_unique(path, access); - } - else if (file_version_numeric >= 2.0 && file_version_numeric < 3.0) - { - hdf_meas_impl_ = std::make_unique(path, access); - } - else if (file_version_numeric >= 3.0 && file_version_numeric < 4.0) - { - hdf_meas_impl_ = std::make_unique(path, access); - } - else if (file_version_numeric >= 4.0 && file_version_numeric < 5.0) - { - hdf_meas_impl_ = std::make_unique(path, access); - } - } - break; - case EcalUtils::Filesystem::Unknown: - default: - return false; - break; - } - - if (access == eAccessType::CREATE) - { - return hdf_meas_impl_ ? EcalUtils::Filesystem::IsDir(path, EcalUtils::Filesystem::OsStyle::Current) : false; - } - else - { - return hdf_meas_impl_ ? hdf_meas_impl_->IsOk() : false; - } -} - -bool eCAL::eh5::HDF5Meas::Close() -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->Close(); - } - - return ret_val; -} - -bool eCAL::eh5::HDF5Meas::IsOk() const -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->IsOk(); - } - - return ret_val; -} - -std::string eCAL::eh5::HDF5Meas::GetFileVersion() const -{ - std::string ret_val; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetFileVersion(); - } - - return ret_val; -} - -size_t eCAL::eh5::HDF5Meas::GetMaxSizePerFile() const -{ - size_t ret_val = 0; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetMaxSizePerFile(); - } - - return ret_val; -} - -void eCAL::eh5::HDF5Meas::SetMaxSizePerFile(size_t size) -{ - if (hdf_meas_impl_) - { - hdf_meas_impl_->SetMaxSizePerFile(size); - } -} - -bool eCAL::eh5::HDF5Meas::IsOneFilePerChannelEnabled() const -{ - if (hdf_meas_impl_ != nullptr) - { - return hdf_meas_impl_->IsOneFilePerChannelEnabled(); - } - return false; -} - -void eCAL::eh5::HDF5Meas::SetOneFilePerChannelEnabled(bool enabled) -{ - if (hdf_meas_impl_ != nullptr) - { - hdf_meas_impl_->SetOneFilePerChannelEnabled(enabled); - } -} - -std::set eCAL::eh5::HDF5Meas::GetChannelNames() const -{ - std::set ret_val; - if (hdf_meas_impl_) - { - std::set escaped_channel_names = hdf_meas_impl_->GetChannelNames(); - for (const std::string& escaped_name : escaped_channel_names) - { - ret_val.emplace(GetUnescapedString(escaped_name)); - } - } - - return ret_val; -} - -bool eCAL::eh5::HDF5Meas::HasChannel(const std::string& channel_name) const -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->HasChannel(GetEscapedTopicname(channel_name)); - } - - return ret_val; -} - -std::string eCAL::eh5::HDF5Meas::GetChannelDescription(const std::string& channel_name) const -{ - std::string ret_val; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetChannelDescription(GetEscapedTopicname(channel_name)); - } - - return ret_val; -} - -void eCAL::eh5::HDF5Meas::SetChannelDescription(const std::string& channel_name, const std::string& description) -{ - if (hdf_meas_impl_) - { - hdf_meas_impl_->SetChannelDescription(GetEscapedTopicname(channel_name), description); - } -} - -std::string eCAL::eh5::HDF5Meas::GetChannelType(const std::string& channel_name) const -{ - std::string ret_val; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetChannelType(GetEscapedTopicname(channel_name)); - } - - return ret_val; -} - -void eCAL::eh5::HDF5Meas::SetChannelType(const std::string& channel_name, const std::string& type) -{ - if (hdf_meas_impl_) - { - hdf_meas_impl_->SetChannelType(GetEscapedTopicname(channel_name), type); - } -} - -long long eCAL::eh5::HDF5Meas::GetMinTimestamp(const std::string& channel_name) const -{ - long long ret_val = 0; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetMinTimestamp(GetEscapedTopicname(channel_name)); - } - - return ret_val; -} - -long long eCAL::eh5::HDF5Meas::GetMaxTimestamp(const std::string& channel_name) const -{ - long long ret_val = 0; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetMaxTimestamp(GetEscapedTopicname(channel_name)); - } - - return ret_val; -} - -bool eCAL::eh5::HDF5Meas::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetEntriesInfo(GetEscapedTopicname(channel_name), entries); - } - - return ret_val; -} - -bool eCAL::eh5::HDF5Meas::GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const -{ - bool ret_val = false; - if (hdf_meas_impl_ && begin < end) - { - ret_val = hdf_meas_impl_->GetEntriesInfoRange(GetEscapedTopicname(channel_name), begin, end, entries); - } - - return ret_val; -} - -bool eCAL::eh5::HDF5Meas::GetEntryDataSize(long long entry_id, size_t& size) const -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - ret_val = hdf_meas_impl_->GetEntryDataSize(entry_id, size); - } - - return ret_val; -} - -bool eCAL::eh5::HDF5Meas::GetEntryData(long long entry_id, void* data) const -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - return hdf_meas_impl_->GetEntryData(entry_id, data); - } - - return ret_val; -} - -void eCAL::eh5::HDF5Meas::SetFileBaseName(const std::string& base_name) -{ - if (hdf_meas_impl_) - { - return hdf_meas_impl_->SetFileBaseName(base_name); - } -} - -bool eCAL::eh5::HDF5Meas::AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) -{ - bool ret_val = false; - if (hdf_meas_impl_) - { - return hdf_meas_impl_->AddEntryToFile(data, size, snd_timestamp, rcv_timestamp, GetEscapedTopicname(channel_name), id, clock); - } - - return ret_val; -} - -void eCAL::eh5::HDF5Meas::ConnectPreSplitCallback(CallbackFunction cb) -{ - if (hdf_meas_impl_) - { - return hdf_meas_impl_->ConnectPreSplitCallback(std::move(cb)); - } -} - -void eCAL::eh5::HDF5Meas::DisconnectPreSplitCallback() -{ - if (hdf_meas_impl_) - { - return hdf_meas_impl_->DisconnectPreSplitCallback(); - } -} diff --git a/contrib/ecalhdf5/src/eh5_meas_api_v2.cpp b/contrib/ecalhdf5/src/eh5_meas_api_v2.cpp new file mode 100644 index 0000000000..7d08adfbaf --- /dev/null +++ b/contrib/ecalhdf5/src/eh5_meas_api_v2.cpp @@ -0,0 +1,284 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief eCALHDF5 measurement class +**/ + +#include + +#include +#include + +#include +#include "datatype_helper.h" + + +namespace { + using namespace eCAL::eh5; + + v3::eAccessType convert(v2::eAccessType v2_access) + { + switch (v2_access) + { + case v2::RDONLY: + return v3::eAccessType::RDONLY; + case v2::CREATE: + return v3::eAccessType::CREATE_V5; + default: + return v3::eAccessType::RDONLY; + } + } + + SChannel createChannel(const std::string& channel_name) + { + return SChannel(channel_name, 0); + } + + + std::set GetChannelsWithName(const std::unique_ptr& hdf_meas_impl_, const std::string& channel_name) + { + const auto all_channels = hdf_meas_impl_->GetChannels(); + std::set named_channels; + for (const auto& channel : all_channels) + { + if (channel.name == channel_name) + { + named_channels.insert(channel); + } + } + return named_channels; + } +} + +using namespace eCAL::eh5::v2; + +eCAL::eh5::v2::HDF5Meas::HDF5Meas() +: hdf_meas_impl_(std::make_unique()) +{} + +// TODO restrict to V5 due to API +eCAL::eh5::v2::HDF5Meas::HDF5Meas(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +: hdf_meas_impl_(std::make_unique(path, convert(access))) +{} + +eCAL::eh5::v2::HDF5Meas::~HDF5Meas() += default; + +bool eCAL::eh5::v2::HDF5Meas::Open(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +{ + return hdf_meas_impl_->Open(path, convert(access)); +} + +bool eCAL::eh5::v2::HDF5Meas::Close() +{ + return hdf_meas_impl_->Close(); +} + +bool eCAL::eh5::v2::HDF5Meas::IsOk() const +{ + return hdf_meas_impl_->IsOk(); +} + +std::string eCAL::eh5::v2::HDF5Meas::GetFileVersion() const +{ + return hdf_meas_impl_->GetFileVersion(); +} + +size_t eCAL::eh5::v2::HDF5Meas::GetMaxSizePerFile() const +{ + return hdf_meas_impl_->GetMaxSizePerFile(); +} + +void eCAL::eh5::v2::HDF5Meas::SetMaxSizePerFile(size_t size) +{ + return hdf_meas_impl_->SetMaxSizePerFile(size); +} + +bool eCAL::eh5::v2::HDF5Meas::IsOneFilePerChannelEnabled() const +{ + return hdf_meas_impl_->IsOneFilePerChannelEnabled(); +} + +void eCAL::eh5::v2::HDF5Meas::SetOneFilePerChannelEnabled(bool enabled) +{ + return hdf_meas_impl_->SetOneFilePerChannelEnabled(enabled); +} + +std::set eCAL::eh5::v2::HDF5Meas::GetChannelNames() const +{ + auto channels = hdf_meas_impl_->GetChannels(); + std::set channel_names; + for (const auto& channel : channels) { + channel_names.insert(channel.name); + } + return channel_names; +} + +bool eCAL::eh5::v2::HDF5Meas::HasChannel(const std::string& channel_name) const +{ + auto named_channels = GetChannelsWithName(hdf_meas_impl_, channel_name); + bool has_channel = false; + for (const auto& channel : named_channels) + { + has_channel |= hdf_meas_impl_->HasChannel(channel); + } + return has_channel; +} + +std::string eCAL::eh5::v2::HDF5Meas::GetChannelDescription(const std::string& channel_name) const +{ + auto datatype_info = GetChannelDataTypeInformation(channel_name); + return datatype_info.descriptor; +} + +void eCAL::eh5::v2::HDF5Meas::SetChannelDescription(const std::string& channel_name, const std::string& description) +{ + const auto& channel = createChannel(channel_name); + auto& current_info = data_type_info_map[channel_name]; + current_info.descriptor = description; + hdf_meas_impl_->SetChannelDataTypeInformation(channel, current_info); +} + +std::string eCAL::eh5::v2::HDF5Meas::GetChannelType(const std::string& channel_name) const +{ + std::string ret_val; + auto datatype_info = GetChannelDataTypeInformation(channel_name); + std::tie(ret_val, std::ignore) = FromInfo(datatype_info); + return ret_val; +} + +void eCAL::eh5::v2::HDF5Meas::SetChannelType(const std::string& channel_name, const std::string& type) +{ + const auto& channel = createChannel(channel_name); + auto& current_info = data_type_info_map[channel_name]; + current_info = CreateInfo(type, current_info.descriptor); + hdf_meas_impl_->SetChannelDataTypeInformation(channel, current_info); +} + +// This function "has" to loose information if there are multople channels in the measurement with the same name +eCAL::eh5::DataTypeInformation eCAL::eh5::v2::HDF5Meas::GetChannelDataTypeInformation(const std::string& channel_name) const +{ + auto named_channels = GetChannelsWithName(hdf_meas_impl_, channel_name); + if (named_channels.size() > 0) + { + return hdf_meas_impl_->GetChannelDataTypeInformation(*named_channels.begin()); + } + return DataTypeInformation{}; +} + +void eCAL::eh5::v2::HDF5Meas::SetChannelDataTypeInformation(const std::string& channel_name, const eCAL::eh5::DataTypeInformation& info) +{ + data_type_info_map[channel_name] = info; + return hdf_meas_impl_->SetChannelDataTypeInformation(createChannel(channel_name), info); +} + +long long eCAL::eh5::v2::HDF5Meas::GetMinTimestamp(const std::string& channel_name) const +{ + auto named_channels = GetChannelsWithName(hdf_meas_impl_, channel_name); + long long min_timestamp = std::numeric_limits::max(); + for (const auto& channel : named_channels) + { + min_timestamp = std::min(min_timestamp, hdf_meas_impl_->GetMinTimestamp(channel)); + } + if (min_timestamp == std::numeric_limits::max()) + return 0; // the old API would return 0 in this case + return min_timestamp; +} + +long long eCAL::eh5::v2::HDF5Meas::GetMaxTimestamp(const std::string& channel_name) const +{ + auto named_channels = GetChannelsWithName(hdf_meas_impl_, channel_name); + long long max_timestamp = std::numeric_limits::min(); + for (const auto& channel : named_channels) + { + max_timestamp = std::max(max_timestamp, hdf_meas_impl_->GetMaxTimestamp(channel)); + } + if (max_timestamp == std::numeric_limits::min()) + return 0; // the old API would return 0 in this case + return max_timestamp; +} + +bool eCAL::eh5::v2::HDF5Meas::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const +{ + // we need to aggregate info from all channels within the measurement with a given name. + auto named_channels = GetChannelsWithName(hdf_meas_impl_, channel_name); + entries.clear(); + bool ret_value{ true }; + for (const auto& channel : named_channels) + { + EntryInfoSet channel_entries; + ret_value &= hdf_meas_impl_->GetEntriesInfo(channel, channel_entries); + entries.insert(channel_entries.begin(), channel_entries.end()); + } + return ret_value; +} + +bool eCAL::eh5::v2::HDF5Meas::GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const +{ + // we need to aggregate info from all channels within the measurement with a given name. + auto named_channels = GetChannelsWithName(hdf_meas_impl_, channel_name); + entries.clear(); + bool ret_value{ true }; + for (const auto& channel : named_channels) + { + EntryInfoSet channel_entries; + ret_value &= hdf_meas_impl_->GetEntriesInfoRange(channel, begin, end, channel_entries); + entries.insert(channel_entries.begin(), channel_entries.end()); + } + return ret_value; +} + +bool eCAL::eh5::v2::HDF5Meas::GetEntryDataSize(long long entry_id, size_t& size) const +{ + return hdf_meas_impl_->GetEntryDataSize(entry_id, size); +} + +bool eCAL::eh5::v2::HDF5Meas::GetEntryData(long long entry_id, void* data) const +{ + return hdf_meas_impl_->GetEntryData(entry_id, data); +} + +void eCAL::eh5::v2::HDF5Meas::SetFileBaseName(const std::string& base_name) +{ + return hdf_meas_impl_->SetFileBaseName(base_name); +} + +bool eCAL::eh5::v2::HDF5Meas::AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) +{ + SWriteEntry entry; + entry.channel = createChannel(channel_name); + entry.data = data; + entry.size = size; + entry.snd_timestamp = snd_timestamp; + entry.rcv_timestamp = rcv_timestamp; + entry.sender_id = id; + entry.clock = clock; + return hdf_meas_impl_->AddEntryToFile(entry); +} + +void eCAL::eh5::v2::HDF5Meas::ConnectPreSplitCallback(CallbackFunction cb) +{ + return hdf_meas_impl_->ConnectPreSplitCallback(std::move(cb)); +} + +void eCAL::eh5::v2::HDF5Meas::DisconnectPreSplitCallback() +{ + return hdf_meas_impl_->DisconnectPreSplitCallback(); +} diff --git a/contrib/ecalhdf5/src/eh5_meas_api_v3.cpp b/contrib/ecalhdf5/src/eh5_meas_api_v3.cpp new file mode 100644 index 0000000000..8feff22ff5 --- /dev/null +++ b/contrib/ecalhdf5/src/eh5_meas_api_v3.cpp @@ -0,0 +1,363 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief eCALHDF5 measurement class +**/ + +#include + +#include + +#include +#include +#include + +#include "eh5_meas_dir.h" +#include "eh5_meas_file_v1.h" +#include "eh5_meas_file_v2.h" +#include "eh5_meas_file_v3.h" +#include "eh5_meas_file_v4.h" +#include "eh5_meas_file_v5.h" +#include "eh5_meas_file_v6.h" + +#include "escape.h" + +namespace +{ + const double file_version_max(6.0); +} + +using namespace eCAL::eh5::v3; + +eCAL::eh5::v3::HDF5Meas::HDF5Meas() += default; + +eCAL::eh5::v3::HDF5Meas::HDF5Meas(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +{ + Open(path, access); +} + +eCAL::eh5::v3::HDF5Meas::~HDF5Meas() += default; + +bool eCAL::eh5::v3::HDF5Meas::Open(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +{ + if (hdf_meas_impl_) + { + Close(); + } + + if (access == eAccessType::CREATE || access == eAccessType::CREATE_V5) + { + EcalUtils::Filesystem::MkPath(path, EcalUtils::Filesystem::OsStyle::Current); + } + + auto type = EcalUtils::Filesystem::GetType(path, EcalUtils::Filesystem::OsStyle::Current); + + switch (type) + { + case EcalUtils::Filesystem::Dir: + { + hdf_meas_impl_ = std::make_unique(path, access); + break; + } + case EcalUtils::Filesystem::RegularFile: + { + hdf_meas_impl_ = std::make_unique(path, access); + + if (!hdf_meas_impl_->IsOk()) + { + hdf_meas_impl_.reset(); + return false; + } + + // no file version at all ? + auto file_version = GetFileVersion(); + if (file_version.empty()) + { + hdf_meas_impl_.reset(); + return false; + } + + // future file version ? + auto file_version_numeric = stod(file_version); + if (file_version_numeric > file_version_max) + { + hdf_meas_impl_.reset(); + return false; + } + + // check if we need to create an older file reader + if (file_version_numeric < 1.0 || file_version_numeric > file_version_max) + { + hdf_meas_impl_.reset(); + } + else if (file_version_numeric >= 1.0 && file_version_numeric < 2.0) + { + hdf_meas_impl_ = std::make_unique(path, access); + } + else if (file_version_numeric >= 2.0 && file_version_numeric < 3.0) + { + hdf_meas_impl_ = std::make_unique(path, access); + } + else if (file_version_numeric >= 3.0 && file_version_numeric < 4.0) + { + hdf_meas_impl_ = std::make_unique(path, access); + } + else if (file_version_numeric >= 4.0 && file_version_numeric < 5.0) + { + hdf_meas_impl_ = std::make_unique(path, access); + } + else if (file_version_numeric >= 5.0 && file_version_numeric < 6.0) + { + hdf_meas_impl_ = std::make_unique(path, access); + } + } + break; + case EcalUtils::Filesystem::Unknown: + default: + return false; + break; + } + + if (access == eAccessType::CREATE || access == eAccessType::CREATE_V5) + { + return hdf_meas_impl_ ? EcalUtils::Filesystem::IsDir(path, EcalUtils::Filesystem::OsStyle::Current) : false; + } + else + { + return hdf_meas_impl_ ? hdf_meas_impl_->IsOk() : false; + } +} + +bool eCAL::eh5::v3::HDF5Meas::Close() +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->Close(); + } + + return ret_val; +} + +bool eCAL::eh5::v3::HDF5Meas::IsOk() const +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->IsOk(); + } + + return ret_val; +} + +std::string eCAL::eh5::v3::HDF5Meas::GetFileVersion() const +{ + std::string ret_val; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetFileVersion(); + } + + return ret_val; +} + +size_t eCAL::eh5::v3::HDF5Meas::GetMaxSizePerFile() const +{ + size_t ret_val = 0; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetMaxSizePerFile(); + } + + return ret_val; +} + +void eCAL::eh5::v3::HDF5Meas::SetMaxSizePerFile(size_t size) +{ + if (hdf_meas_impl_) + { + hdf_meas_impl_->SetMaxSizePerFile(size); + } +} + +bool eCAL::eh5::v3::HDF5Meas::IsOneFilePerChannelEnabled() const +{ + if (hdf_meas_impl_ != nullptr) + { + return hdf_meas_impl_->IsOneFilePerChannelEnabled(); + } + return false; +} + +void eCAL::eh5::v3::HDF5Meas::SetOneFilePerChannelEnabled(bool enabled) +{ + if (hdf_meas_impl_ != nullptr) + { + hdf_meas_impl_->SetOneFilePerChannelEnabled(enabled); + } +} + +std::set eCAL::eh5::v3::HDF5Meas::GetChannels() const +{ + std::set ret_val; + if (hdf_meas_impl_) + { + auto escaped_channels = hdf_meas_impl_->GetChannels(); + for (const auto& escaped_channel : escaped_channels) + { + ret_val.emplace(GetUnescapedString(escaped_channel.name), escaped_channel.id); + } + } + + return ret_val; +} + +bool eCAL::eh5::v3::HDF5Meas::HasChannel(const eCAL::eh5::SChannel& channel) const +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->HasChannel(GetEscapedTopicname(channel)); + } + + return ret_val; +} + +eCAL::eh5::DataTypeInformation eCAL::eh5::v3::HDF5Meas::GetChannelDataTypeInformation(const SChannel& channel) const +{ + eCAL::eh5::DataTypeInformation ret_val; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetChannelDataTypeInformation(GetEscapedTopicname(channel)); + } + + return ret_val; +} + +void eCAL::eh5::v3::HDF5Meas::SetChannelDataTypeInformation(const SChannel& channel, const eCAL::eh5::DataTypeInformation& info) +{ + if (hdf_meas_impl_) + { + hdf_meas_impl_->SetChannelDataTypeInformation(GetEscapedTopicname(channel), info); + } +} + +long long eCAL::eh5::v3::HDF5Meas::GetMinTimestamp(const SChannel& channel) const +{ + long long ret_val = 0; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetMinTimestamp(GetEscapedTopicname(channel)); + } + + return ret_val; +} + +long long eCAL::eh5::v3::HDF5Meas::GetMaxTimestamp(const SChannel& channel) const +{ + long long ret_val = 0; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetMaxTimestamp(GetEscapedTopicname(channel)); + } + + return ret_val; +} + +bool eCAL::eh5::v3::HDF5Meas::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetEntriesInfo(GetEscapedTopicname(channel), entries); + } + + return ret_val; +} + +bool eCAL::eh5::v3::HDF5Meas::GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const +{ + bool ret_val = false; + if (hdf_meas_impl_ && begin < end) + { + ret_val = hdf_meas_impl_->GetEntriesInfoRange(GetEscapedTopicname(channel), begin, end, entries); + } + + return ret_val; +} + +bool eCAL::eh5::v3::HDF5Meas::GetEntryDataSize(long long entry_id, size_t& size) const +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + ret_val = hdf_meas_impl_->GetEntryDataSize(entry_id, size); + } + + return ret_val; +} + +bool eCAL::eh5::v3::HDF5Meas::GetEntryData(long long entry_id, void* data) const +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + return hdf_meas_impl_->GetEntryData(entry_id, data); + } + + return ret_val; +} + +void eCAL::eh5::v3::HDF5Meas::SetFileBaseName(const std::string& base_name) +{ + if (hdf_meas_impl_) + { + return hdf_meas_impl_->SetFileBaseName(base_name); + } +} + +bool eCAL::eh5::v3::HDF5Meas::AddEntryToFile(const SWriteEntry& entry) +{ + bool ret_val = false; + if (hdf_meas_impl_) + { + return hdf_meas_impl_->AddEntryToFile(GetEscapedEntry(entry)); + } + + return ret_val; +} + +void eCAL::eh5::v3::HDF5Meas::ConnectPreSplitCallback(CallbackFunction cb) +{ + if (hdf_meas_impl_) + { + return hdf_meas_impl_->ConnectPreSplitCallback(std::move(cb)); + } +} + +void eCAL::eh5::v3::HDF5Meas::DisconnectPreSplitCallback() +{ + if (hdf_meas_impl_) + { + return hdf_meas_impl_->DisconnectPreSplitCallback(); + } +} diff --git a/contrib/ecalhdf5/src/eh5_meas_dir.cpp b/contrib/ecalhdf5/src/eh5_meas_dir.cpp index d2750d3184..d53ed26460 100644 --- a/contrib/ecalhdf5/src/eh5_meas_dir.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_dir.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,31 +24,34 @@ #include "eh5_meas_dir.h" #include "escape.h" +#define NOMINMAX #ifdef WIN32 #include #else #include #endif //WIN32 -#include -#include #include +#include +#include +#include #include #include #include "eh5_meas_file_writer_v5.h" +#include "eh5_meas_file_writer_v6.h" // TODO: Test the one-file-per-channel setting with gtest constexpr unsigned int kDefaultMaxFileSizeMB = 1000; eCAL::eh5::HDF5MeasDir::HDF5MeasDir() - : access_ (RDONLY) // Temporarily set it to RDONLY, so the leading "Close()" from the Open() function will not operate on the uninitialized variable. + : access_ (v3::eAccessType::RDONLY) // Temporarily set it to RDONLY, so the leading "Close()" from the Open() function will not operate on the uninitialized variable. , one_file_per_channel_(false) , max_size_per_file_ (kDefaultMaxFileSizeMB * 1024 * 1024) , cb_pre_split_ (nullptr) {} -eCAL::eh5::HDF5MeasDir::HDF5MeasDir(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +eCAL::eh5::HDF5MeasDir::HDF5MeasDir(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) : access_ (access) , one_file_per_channel_(false) , max_size_per_file_ (kDefaultMaxFileSizeMB * 1024 * 1024) @@ -66,7 +69,7 @@ eCAL::eh5::HDF5MeasDir::~HDF5MeasDir() HDF5MeasDir::Close(); } -bool eCAL::eh5::HDF5MeasDir::Open(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +bool eCAL::eh5::HDF5MeasDir::Open(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) { // call the function via its class becase it's a virtual function that is called directly/indirectly in constructor/destructor,- // where the vtable is not created yet or it's destructed. @@ -80,10 +83,11 @@ bool eCAL::eh5::HDF5MeasDir::Open(const std::string& path, eAccessType access /* switch (access) { - case eCAL::eh5::RDONLY: + case eCAL::eh5::v3::eAccessType::RDONLY: //case eCAL::eh5::RDWR: return OpenRX(path, access); - case eCAL::eh5::CREATE: + case eCAL::eh5::v3::eAccessType::CREATE: + case eCAL::eh5::v3::eAccessType::CREATE_V5: output_dir_ = path; return true; default: @@ -97,7 +101,7 @@ bool eCAL::eh5::HDF5MeasDir::Close() { bool successfully_closed{ true }; - if (access_ == eAccessType::CREATE) + if (access_ == v3::eAccessType::CREATE || access_ == v3::eAccessType::CREATE_V5) { // Close all existing file writers for (auto& file_writer : file_writers_) @@ -135,10 +139,11 @@ bool eCAL::eh5::HDF5MeasDir::IsOk() const { switch (access_) { - case eCAL::eh5::RDONLY: + case eCAL::eh5::v3::eAccessType::RDONLY: //case eCAL::eh5::RDWR: return !file_readers_.empty() && !entries_by_id_.empty(); - case eCAL::eh5::CREATE: + case eCAL::eh5::v3::eAccessType::CREATE: + case eCAL::eh5::v3::eAccessType::CREATE_V5: return true; default: return false; @@ -182,129 +187,109 @@ void eCAL::eh5::HDF5MeasDir::SetOneFilePerChannelEnabled(bool enabled) one_file_per_channel_ = enabled; } -std::set eCAL::eh5::HDF5MeasDir::GetChannelNames() const +std::set eCAL::eh5::HDF5MeasDir::GetChannels() const { - std::set channels; + std::set channels; + for (const auto& chn : channels_info_) channels.insert(chn.first); return channels; } -bool eCAL::eh5::HDF5MeasDir::HasChannel(const std::string& channel_name) const +bool eCAL::eh5::HDF5MeasDir::HasChannel(const eCAL::eh5::SChannel& channel) const { - return channels_info_.count(channel_name) != 0; + return channels_info_.find(channel) != channels_info_.end(); } -std::string eCAL::eh5::HDF5MeasDir::GetChannelDescription(const std::string& channel_name) const +eCAL::eh5::DataTypeInformation eCAL::eh5::HDF5MeasDir::GetChannelDataTypeInformation(const SChannel& channel) const { - std::string ret_val; - - const auto& found = channels_info_.find(channel_name); + eCAL::eh5::DataTypeInformation ret_val; + const auto& found = channels_info_.find(channel); if (found != channels_info_.end()) { - ret_val = found->second.description; + ret_val = found->second.info; } return ret_val; } -void eCAL::eh5::HDF5MeasDir::SetChannelDescription(const std::string& channel_name, const std::string& description) +// TODO: this seems fishy. Do we need to escape? +void eCAL::eh5::HDF5MeasDir::SetChannelDataTypeInformation(const SChannel& channel, const eCAL::eh5::DataTypeInformation& info) { // Get an existing writer or create a new one - auto file_writer_it = GetWriter(channel_name); - file_writer_it->second->SetChannelDescription(channel_name, description); -} - -std::string eCAL::eh5::HDF5MeasDir::GetChannelType(const std::string& channel_name) const -{ - std::string ret_val; + auto file_writer_it = GetWriter(channel); + file_writer_it->second->SetChannelDataTypeInformation(channel, info); - const auto& found = channels_info_.find(channel_name); - - if (found != channels_info_.end()) - { - ret_val = found->second.type; - } - return ret_val; -} - -void eCAL::eh5::HDF5MeasDir::SetChannelType(const std::string& channel_name, const std::string& type) -{ - // Get an existing writer or create a new one - auto file_writer_it = GetWriter(channel_name); - file_writer_it->second->SetChannelType(channel_name, type); + // Let's save them in case we need to query them + channels_info_[channel] = ChannelInfo(info); } -long long eCAL::eh5::HDF5MeasDir::GetMinTimestamp(const std::string& channel_name) const +long long eCAL::eh5::HDF5MeasDir::GetMinTimestamp(const SChannel& channel) const { - long long ret_val = 0; + long long min_timestamp = std::numeric_limits::max(); + const auto& channel_entries = entries_by_chn_.find(channel); - const auto& found = entries_by_chn_.find(channel_name); - - if (found != entries_by_chn_.end()) + if (channel_entries != entries_by_chn_.end()) { - if (!found->second.empty()) + if (!channel_entries->second.empty()) { - ret_val = found->second.begin()->RcvTimestamp; + min_timestamp = channel_entries->second.begin()->RcvTimestamp; } } - return ret_val; + return min_timestamp; } -long long eCAL::eh5::HDF5MeasDir::GetMaxTimestamp(const std::string& channel_name) const +long long eCAL::eh5::HDF5MeasDir::GetMaxTimestamp(const SChannel& channel) const { - long long ret_val = 0; - - const auto& found = entries_by_chn_.find(channel_name); + long long max_timestamp = std::numeric_limits::min(); + const auto& channel_entries = entries_by_chn_.find(channel); - if (found != entries_by_chn_.end()) + if (channel_entries != entries_by_chn_.end()) { - if (!found->second.empty()) + if (!channel_entries->second.empty()) { - ret_val = found->second.rbegin()->RcvTimestamp; + max_timestamp = channel_entries->second.rbegin()->RcvTimestamp; } } - return ret_val; + return max_timestamp; } -bool eCAL::eh5::HDF5MeasDir::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const +bool eCAL::eh5::HDF5MeasDir::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const { entries.clear(); - const auto& found = entries_by_chn_.find(channel_name); - - if (found != entries_by_chn_.end()) + const auto& channel_it = entries_by_chn_.find(channel); + if (channel_it == entries_by_chn_.end()) { - entries = found->second; + return false; } + entries = channel_it->second; + return !entries.empty(); } -bool eCAL::eh5::HDF5MeasDir::GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const +bool eCAL::eh5::HDF5MeasDir::GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const { - bool ret_val = false; - entries.clear(); - const auto& found = entries_by_chn_.find(channel_name); - - if (found != entries_by_chn_.end()) + const auto& channel_it = entries_by_chn_.find(channel); + if (channel_it == entries_by_chn_.end()) { - if (begin == 0) begin = entries.begin()->RcvTimestamp; - if (end == 0) end = entries.rbegin()->RcvTimestamp; + return false; + } - const auto& lower = found->second.lower_bound(SEntryInfo(begin, 0, 0)); - const auto& upper = found->second.upper_bound(SEntryInfo(end, 0, 0)); + if (begin == 0) begin = entries.begin()->RcvTimestamp; + if (end == 0) end = entries.rbegin()->RcvTimestamp; - entries.insert(lower, upper); - ret_val = true; - } + const auto& lower = channel_it->second.lower_bound(SEntryInfo(begin, 0, 0)); + const auto& upper = channel_it->second.upper_bound(SEntryInfo(end, 0, 0)); - return ret_val; + entries.insert(lower, upper); + return true; } bool eCAL::eh5::HDF5MeasDir::GetEntryDataSize(long long entry_id, size_t& size) const @@ -334,9 +319,9 @@ void eCAL::eh5::HDF5MeasDir::SetFileBaseName(const std::string& base_name) base_name_ = base_name; } -bool eCAL::eh5::HDF5MeasDir::AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) +bool eCAL::eh5::HDF5MeasDir::AddEntryToFile(const SWriteEntry& entry) { - if ((access_ != CREATE) + if ((access_ == v3::eAccessType::RDONLY) || (output_dir_.empty()) || (base_name_.empty())) { @@ -344,10 +329,10 @@ bool eCAL::eh5::HDF5MeasDir::AddEntryToFile(const void* data, const unsigned lon } // Get an existing writer or create a new one - auto file_writer_it = GetWriter(channel_name); - + auto file_writer_it = GetWriter(entry.channel); + // Use the writer that was either found or created to actually write the data - return file_writer_it->second->AddEntryToFile(data, size, snd_timestamp, rcv_timestamp, channel_name, id, clock); + return file_writer_it->second->AddEntryToFile(entry); } void eCAL::eh5::HDF5MeasDir::ConnectPreSplitCallback(CallbackFunction cb) @@ -439,9 +424,9 @@ std::list eCAL::eh5::HDF5MeasDir::GetHdfFiles(const std::string& pa return paths; } -bool eCAL::eh5::HDF5MeasDir::OpenRX(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +bool eCAL::eh5::HDF5MeasDir::OpenRX(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) { - if (access != eAccessType::RDONLY /*&& access != eAccessType::RDWR*/) return false; + if (access != v3::eAccessType::RDONLY /*&& access != eAccessType::RDWR*/) return false; auto files = GetHdfFiles(path); @@ -449,29 +434,19 @@ bool eCAL::eh5::HDF5MeasDir::OpenRX(const std::string& path, eAccessType access for (const auto& file_path : files) { - auto reader = new eCAL::eh5::HDF5Meas(file_path); + auto reader = new eCAL::eh5::v3::HDF5Meas(file_path); if (reader->IsOk()) { - auto channels = reader->GetChannelNames(); + auto channels = reader->GetChannels(); for (const auto& channel : channels) { - auto escaped_name = GetEscapedTopicname(channel); - auto description = reader->GetChannelDescription(channel); - - if (channels_info_.find(escaped_name) == channels_info_.end()) - { - channels_info_[escaped_name] = ChannelInfo(reader->GetChannelType(channel), description); - } - else - { - if (!description.empty()) - { - channels_info_[escaped_name].description = description; - } - } + auto escaped_channel = GetEscapedTopicname(channel); + auto info = reader->GetChannelDataTypeInformation(escaped_channel); - channels_info_[escaped_name].files.push_back(reader); + auto& channel_info = channels_info_[escaped_channel]; + channel_info.info = info; + channel_info.files.push_back(reader); EntryInfoSet entries; if (reader->GetEntriesInfo(channel, entries)) @@ -480,7 +455,7 @@ bool eCAL::eh5::HDF5MeasDir::OpenRX(const std::string& path, eAccessType access { entries_by_id_[id] = EntryInfo(entry.ID, reader); entry.ID = id; - entries_by_chn_[escaped_name].insert(entry); + entries_by_chn_[escaped_channel].insert(entry); id++; } } @@ -497,16 +472,24 @@ bool eCAL::eh5::HDF5MeasDir::OpenRX(const std::string& path, eAccessType access return !file_readers_.empty(); } -::eCAL::eh5::HDF5MeasDir::FileWriterMap::iterator eCAL::eh5::HDF5MeasDir::GetWriter(const std::string& channel_name) +::eCAL::eh5::HDF5MeasDir::FileWriterMap::iterator eCAL::eh5::HDF5MeasDir::GetWriter(const SChannel& channel) { + const auto& channel_name{ channel.name }; // Look for an existing writer. When creating 1 file per channel, the channel // name is used as key. Otherwise, emptystring is used as "generic" key and // the same writer is used for all channels. FileWriterMap::iterator file_writer_it = file_writers_.find(one_file_per_channel_ ? channel_name : ""); if (file_writer_it == file_writers_.end()) { - // No appropriate file writer was found. Let's create a new one! - file_writer_it = file_writers_.emplace(one_file_per_channel_ ? channel_name : "", std::make_unique<::eCAL::eh5::HDF5MeasFileWriterV5>()).first; + if (access_ == v3::eAccessType::CREATE) + { + // No appropriate file writer was found. Let's create a new one! + file_writer_it = file_writers_.emplace(one_file_per_channel_ ? channel_name : "", std::make_unique<::eCAL::eh5::HDF5MeasFileWriterV6>()).first; + } + else + { + file_writer_it = file_writers_.emplace(one_file_per_channel_ ? channel_name : "", std::make_unique<::eCAL::eh5::HDF5MeasFileWriterV5>()).first; + } // Set the current parameters to the new file writer file_writer_it->second->SetMaxSizePerFile(GetMaxSizePerFile()); diff --git a/contrib/ecalhdf5/src/eh5_meas_dir.h b/contrib/ecalhdf5/src/eh5_meas_dir.h index 30d2308970..f7392e3b6c 100644 --- a/contrib/ecalhdf5/src/eh5_meas_dir.h +++ b/contrib/ecalhdf5/src/eh5_meas_dir.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,7 +52,7 @@ namespace eCAL * * @param path input file path **/ - explicit HDF5MeasDir(const std::string& path, eAccessType access = eAccessType::RDONLY); + explicit HDF5MeasDir(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); /** * @brief Destructor @@ -67,7 +67,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool Open(const std::string& path, eAccessType access = eAccessType::RDONLY) override; + bool Open(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY) override; /** * @brief Close file @@ -127,54 +127,39 @@ namespace eCAL void SetOneFilePerChannelEnabled(bool enabled) override; /** - * @brief Get the available channel names of the current opened file / measurement - * - * @return channel names - **/ - std::set GetChannelNames() const override; + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids + **/ + std::set GetChannels() const override; /** - * @brief Check if channel exists in measurement - * - * @param channel_name name of the channel - * - * @return true if exists, false otherwise + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise **/ - bool HasChannel(const std::string& channel_name) const override; + bool HasChannel(const eCAL::eh5::SChannel& channel) const override; /** - * @brief Get the channel description for the given channel - * - * @param channel_name channel name - * - * @return channel description + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type **/ - std::string GetChannelDescription(const std::string& channel_name) const override; + DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const override; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel - **/ - void SetChannelDescription(const std::string& channel_name, const std::string& description) override; - - /** - * @brief Gets the channel type of the given channel - * - * @param channel_name channel name - * - * @return channel type - **/ - std::string GetChannelType(const std::string& channel_name) const override; - - /** - * @brief Set type of the given channel - * - * @param channel_name channel name - * @param type type of the channel + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type **/ - void SetChannelType(const std::string& channel_name, const std::string& type) override; + void SetChannelDataTypeInformation(const SChannel& channel, const DataTypeInformation& info) override; /** * @brief Gets minimum timestamp for specified channel @@ -183,7 +168,7 @@ namespace eCAL * * @return minimum timestamp value **/ - long long GetMinTimestamp(const std::string& channel_name) const override; + long long GetMinTimestamp(const SChannel& channel) const override; /** * @brief Gets maximum timestamp for specified channel @@ -192,7 +177,7 @@ namespace eCAL * * @return maximum timestamp value **/ - long long GetMaxTimestamp(const std::string& channel_name) const override; + long long GetMaxTimestamp(const SChannel& channel) const override; /** * @brief Gets the header info for all data entries for the given channel @@ -203,7 +188,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) @@ -216,7 +201,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const override; + bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const override; /** * @brief Gets data size of a specific entry @@ -252,13 +237,13 @@ namespace eCAL * @param size size of the data * @param snd_timestamp send timestamp * @param rcv_timestamp receive timestamp - * @param channel_name channel name + * @param channel channel * @param id message id * @param clock message clock * * @return true if succeeds, false if it fails **/ - bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) override; + bool AddEntryToFile(const SWriteEntry& entry) override; typedef std::function CallbackFunction; /** @@ -280,34 +265,32 @@ namespace eCAL protected: struct ChannelInfo { - std::string type; - std::string description; - std::list files; + DataTypeInformation info; + std::list files; ChannelInfo() = default; - ChannelInfo(const std::string& type_, const std::string& description_) - : type(type_) - , description(description_) + ChannelInfo(const DataTypeInformation& info_) + : info(info_) {} }; struct EntryInfo { - long long file_id; - const eCAL::eh5::HDF5Meas* reader; + long long file_id; + const eCAL::eh5::v3::HDF5Meas* reader; EntryInfo() : file_id(0), reader(nullptr) {} - EntryInfo(long long file_id_, const eCAL::eh5::HDF5Meas* reader_) + EntryInfo(long long file_id_, const eCAL::eh5::v3::HDF5Meas* reader_) : file_id(file_id_) , reader(reader_) {} }; - typedef std::list HDF5Files; - typedef std::unordered_map ChannelInfoUMap; - typedef std::unordered_map EntriesByIdUMap; - typedef std::unordered_map EntriesByChannelUMap; + typedef std::list HDF5Files; + typedef std::unordered_map ChannelInfoUMap; + typedef std::unordered_map EntriesByIdUMap; + typedef std::unordered_map EntriesByChannelUMap; HDF5Files file_readers_; ChannelInfoUMap channels_info_; @@ -324,7 +307,7 @@ namespace eCAL typedef std::map Channels; Channels channels_; - eAccessType access_; + v3::eAccessType access_; std::list GetHdfFiles(const std::string& path) const; @@ -335,7 +318,7 @@ namespace eCAL return std::equal(end.rbegin(), end.rend(), str.rbegin()); } - bool OpenRX(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/); + bool OpenRX(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/); // ===================================================================== @@ -367,7 +350,7 @@ namespace eCAL * * @return an iterator to the writer */ - FileWriterMap::iterator GetWriter(const std::string& channel_name); + FileWriterMap::iterator GetWriter(const SChannel& channel); }; } // namespace eh5 } // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v1.cpp b/contrib/ecalhdf5/src/eh5_meas_file_v1.cpp index 02fed6dbec..a6a227d7e7 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v1.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_file_v1.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ #include "hdf5.h" #include +#include "datatype_helper.h" #include @@ -37,7 +38,7 @@ eCAL::eh5::HDF5MeasFileV1::HDF5MeasFileV1() } -eCAL::eh5::HDF5MeasFileV1::HDF5MeasFileV1(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +eCAL::eh5::HDF5MeasFileV1::HDF5MeasFileV1(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) : file_id_(-1) { #ifndef _DEBUG @@ -58,7 +59,7 @@ eCAL::eh5::HDF5MeasFileV1::~HDF5MeasFileV1() } -bool eCAL::eh5::HDF5MeasFileV1::Open(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +bool eCAL::eh5::HDF5MeasFileV1::Open(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) { entries_.clear(); @@ -68,7 +69,7 @@ bool eCAL::eh5::HDF5MeasFileV1::Open(const std::string& path, eAccessType access if (file_id_ > 0) HDF5MeasFileV1::Close(); - if (access != eAccessType::RDONLY) + if (access != v3::eAccessType::RDONLY) { ReportUnsupportedAction(); return false; @@ -78,11 +79,11 @@ bool eCAL::eh5::HDF5MeasFileV1::Open(const std::string& path, eAccessType access if (HDF5MeasFileV1::IsOk()) { - auto channels = HDF5MeasFileV1::GetChannelNames(); + auto channels = HDF5MeasFileV1::GetChannels(); if (channels.size() == 1) { - channel_name_ = *channels.begin(); - HDF5MeasFileV1::GetEntriesInfo(channel_name_, entries_); + auto channel = *channels.begin(); + HDF5MeasFileV1::GetEntriesInfo(channel, entries_); } } @@ -143,58 +144,47 @@ void eCAL::eh5::HDF5MeasFileV1::SetOneFilePerChannelEnabled(bool /*enabled*/) ReportUnsupportedAction(); } -std::set eCAL::eh5::HDF5MeasFileV1::GetChannelNames() const +std::set eCAL::eh5::HDF5MeasFileV1::GetChannels() const { - std::set channels; + std::set channels; std::string channel_name; GetAttributeValue(file_id_, kChnNameAttribTitle, channel_name); if (!channel_name.empty()) - channels.insert(channel_name); + channels.insert(eCAL::experimental::measurement::base::CreateChannel(channel_name)); return channels; } - -bool eCAL::eh5::HDF5MeasFileV1::HasChannel(const std::string& channel_name) const -{ - auto channels = GetChannelNames(); - - return std::find(channels.cbegin(), channels.cend(), channel_name) != channels.end(); -} - -std::string eCAL::eh5::HDF5MeasFileV1::GetChannelDescription(const std::string& channel_name) const +bool eCAL::eh5::HDF5MeasFileV1::HasChannel(const eCAL::eh5::SChannel& channel) const { - std::string description; - - if (EcalUtils::String::Icompare(channel_name, channel_name_)) - GetAttributeValue(file_id_, kChnDescAttrTitle, description); + auto channels = GetChannels(); - return description; + return std::find(channels.cbegin(), channels.cend(), channel) != channels.end(); } -void eCAL::eh5::HDF5MeasFileV1::SetChannelDescription(const std::string& /*channel_name*/, const std::string& /*description*/) -{ - ReportUnsupportedAction(); -} - -std::string eCAL::eh5::HDF5MeasFileV1::GetChannelType(const std::string& channel_name) const +eCAL::eh5::DataTypeInformation eCAL::eh5::HDF5MeasFileV1::GetChannelDataTypeInformation(const SChannel& channel) const { std::string type; - if (EcalUtils::String::Icompare(channel_name, channel_name_)) + if (EcalUtils::String::Icompare(channel.name, channel_name_)) GetAttributeValue(file_id_, kChnTypeAttrTitle, type); - return type; + std::string description; + + if (EcalUtils::String::Icompare(channel.name, channel_name_)) + GetAttributeValue(file_id_, kChnDescAttrTitle, description); + + return CreateInfo(type, description); } -void eCAL::eh5::HDF5MeasFileV1::SetChannelType(const std::string& /*channel_name*/, const std::string& /*type*/) +void eCAL::eh5::HDF5MeasFileV1::SetChannelDataTypeInformation(const SChannel& /*channel*/, const eCAL::eh5::DataTypeInformation& /*info*/) { ReportUnsupportedAction(); } -long long eCAL::eh5::HDF5MeasFileV1::GetMinTimestamp(const std::string& /*channel_name*/) const +long long eCAL::eh5::HDF5MeasFileV1::GetMinTimestamp(const SChannel& /*channel_name*/) const { long long ret_val = 0; @@ -206,7 +196,7 @@ long long eCAL::eh5::HDF5MeasFileV1::GetMinTimestamp(const std::string& /*channe return ret_val; } -long long eCAL::eh5::HDF5MeasFileV1::GetMaxTimestamp(const std::string& /*channel_name*/) const +long long eCAL::eh5::HDF5MeasFileV1::GetMaxTimestamp(const SChannel& /*channel_name*/) const { long long ret_val = 0; @@ -218,11 +208,11 @@ long long eCAL::eh5::HDF5MeasFileV1::GetMaxTimestamp(const std::string& /*channe return ret_val; } -bool eCAL::eh5::HDF5MeasFileV1::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const +bool eCAL::eh5::HDF5MeasFileV1::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const { entries.clear(); - if (!EcalUtils::String::Icompare(channel_name, channel_name_)) return false; + if (!EcalUtils::String::Icompare(channel.name, channel_name_)) return false; if (!HDF5MeasFileV1::IsOk()) return false; @@ -254,7 +244,7 @@ bool eCAL::eh5::HDF5MeasFileV1::GetEntriesInfo(const std::string& channel_name, return (status >= 0); } -bool eCAL::eh5::HDF5MeasFileV1::GetEntriesInfoRange(const std::string& /*channel_name*/, long long begin, long long end, EntryInfoSet& entries) const +bool eCAL::eh5::HDF5MeasFileV1::GetEntriesInfoRange(const SChannel& /*channel_name*/, long long begin, long long end, EntryInfoSet& entries) const { bool ret_val = false; @@ -315,7 +305,7 @@ void eCAL::eh5::HDF5MeasFileV1::SetFileBaseName(const std::string& /*base_name*/ ReportUnsupportedAction(); } -bool eCAL::eh5::HDF5MeasFileV1::AddEntryToFile(const void* /*data*/, const unsigned long long& /*size*/, const long long& /*snd_timestamp*/, const long long& /*rcv_timestamp*/, const std::string& /*channel_name*/, long long /*id*/, long long /*clock*/) +bool eCAL::eh5::HDF5MeasFileV1::AddEntryToFile(const SWriteEntry& /*entry*/) { ReportUnsupportedAction(); return false; @@ -387,5 +377,5 @@ bool eCAL::eh5::HDF5MeasFileV1::GetAttributeValue(hid_t obj_id, const std::strin void eCAL::eh5::HDF5MeasFileV1::ReportUnsupportedAction() { - std::cout << "eCALHDF5 file version bellow 2.0 support only readonly access type. Desired action not supported.\n"; + std::cout << "eCALHDF5 file version below 2.0 support only readonly access type. Desired action not supported.\n"; } diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v1.h b/contrib/ecalhdf5/src/eh5_meas_file_v1.h index 38cf339eb7..7b8e0565cc 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v1.h +++ b/contrib/ecalhdf5/src/eh5_meas_file_v1.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ namespace eCAL * * @param path input file path **/ - explicit HDF5MeasFileV1(const std::string& path, eAccessType access = eAccessType::RDONLY); + explicit HDF5MeasFileV1(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); /** * @brief Destructor @@ -58,7 +58,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool Open(const std::string& path, eAccessType access = eAccessType::RDONLY) override; + bool Open(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY) override; /** * @brief Close file @@ -117,56 +117,40 @@ namespace eCAL */ void SetOneFilePerChannelEnabled(bool enabled) override; - /** - * @brief Get the available channel names of the current opened file / measurement - * - * @return channel names + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids **/ - std::set GetChannelNames() const override; + std::set GetChannels() const override; /** - * @brief Check if channel exists in measurement - * - * @param channel_name name of the channel - * - * @return true if exists, false otherwise + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise **/ - bool HasChannel(const std::string& channel_name) const override; + bool HasChannel(const eCAL::eh5::SChannel& channel) const override; /** - * @brief Get the channel description for the given channel - * - * @param channel_name channel name - * - * @return channel description + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type **/ - std::string GetChannelDescription(const std::string& channel_name) const override; + DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const override; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel - **/ - void SetChannelDescription(const std::string& channel_name, const std::string& description) override; - - /** - * @brief Gets the channel type of the given channel - * - * @param channel_name channel name - * - * @return channel type - **/ - std::string GetChannelType(const std::string& channel_name) const override; - - /** - * @brief Set type of the given channel - * - * @param channel_name channel name - * @param type type of the channel + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type **/ - void SetChannelType(const std::string& channel_name, const std::string& type) override; + void SetChannelDataTypeInformation(const SChannel& channel, const DataTypeInformation& info) override; /** * @brief Gets minimum timestamp for specified channel @@ -175,7 +159,7 @@ namespace eCAL * * @return minimum timestamp value **/ - long long GetMinTimestamp(const std::string& channel_name) const override; + long long GetMinTimestamp(const SChannel& channel) const override; /** * @brief Gets maximum timestamp for specified channel @@ -184,7 +168,7 @@ namespace eCAL * * @return maximum timestamp value **/ - long long GetMaxTimestamp(const std::string& channel_name) const override; + long long GetMaxTimestamp(const SChannel& channel) const override; /** * @brief Gets the header info for all data entries for the given channel @@ -195,7 +179,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) @@ -208,7 +192,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const override; + bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const override; /** * @brief Gets data size of a specific entry @@ -250,7 +234,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) override; + bool AddEntryToFile(const SWriteEntry& entry) override; typedef std::function CallbackFunction; /** diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v2.cpp b/contrib/ecalhdf5/src/eh5_meas_file_v2.cpp index 008623edc3..c621311f09 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v2.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_file_v2.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ **/ #include "eh5_meas_file_v2.h" +#include "hdf5_helper.h" +#include "datatype_helper.h" #include "hdf5.h" #include @@ -38,7 +40,7 @@ eCAL::eh5::HDF5MeasFileV2::HDF5MeasFileV2() #endif // _DEBUG } -eCAL::eh5::HDF5MeasFileV2::HDF5MeasFileV2(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +eCAL::eh5::HDF5MeasFileV2::HDF5MeasFileV2(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) : file_id_(-1) { #ifndef _DEBUG @@ -58,11 +60,11 @@ eCAL::eh5::HDF5MeasFileV2::~HDF5MeasFileV2() } -bool eCAL::eh5::HDF5MeasFileV2::Open(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) +bool eCAL::eh5::HDF5MeasFileV2::Open(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) { if (file_id_ > 0) Close(); if (path.empty()) return false; - if (access != eAccessType::RDONLY) return false; + if (access != v3::eAccessType::RDONLY) return false; file_id_ = H5Fopen(path.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT); @@ -95,7 +97,7 @@ bool eCAL::eh5::HDF5MeasFileV2::IsOk() const std::string eCAL::eh5::HDF5MeasFileV2::GetFileVersion() const { std::string file_version; - GetAttributeValue(file_id_, kFileVerAttrTitle, file_version); + GetAttribute(file_id_, kFileVerAttrTitle, file_version); return file_version; } @@ -120,78 +122,59 @@ void eCAL::eh5::HDF5MeasFileV2::SetOneFilePerChannelEnabled(bool /*enabled*/) { } -std::set eCAL::eh5::HDF5MeasFileV2::GetChannelNames() const +std::set eCAL::eh5::HDF5MeasFileV2::GetChannels() const { - std::set channels_set; + std::set channels_set; - std::string channel_names; - GetAttributeValue(file_id_, kChnAttrTitle, channel_names); + std::string combined_channel_names; + GetAttribute(file_id_, kChnAttrTitle, combined_channel_names); - std::list channels; - EcalUtils::String::Split(channel_names, ",", channels); + std::list channel_name_list; + EcalUtils::String::Split(combined_channel_names, ",", channel_name_list); - for (const auto& channel : channels) - channels_set.insert(channel); + for (const auto& channel_name : channel_name_list) + channels_set.insert(eCAL::experimental::measurement::base::CreateChannel(channel_name)); return channels_set; } - -bool eCAL::eh5::HDF5MeasFileV2::HasChannel(const std::string& channel_name) const +bool eCAL::eh5::HDF5MeasFileV2::HasChannel(const eCAL::eh5::SChannel& channel) const { - auto channels = GetChannelNames(); + auto channels = GetChannels(); - return std::find(channels.cbegin(), channels.cend(), channel_name) != channels.end(); + return std::find(channels.cbegin(), channels.cend(), channel) != channels.end(); } -std::string eCAL::eh5::HDF5MeasFileV2::GetChannelDescription(const std::string& channel_name) const +eCAL::eh5::DataTypeInformation eCAL::eh5::HDF5MeasFileV2::GetChannelDataTypeInformation(const SChannel& channel) const { + std::string type; std::string description; if (this->IsOk()) { - auto dataset_id = H5Dopen(file_id_, channel_name.c_str(), H5P_DEFAULT); + auto dataset_id = H5Dopen(file_id_, channel.name.c_str(), H5P_DEFAULT); if (dataset_id >= 0) { - GetAttributeValue(dataset_id, kChnDescAttrTitle, description); + GetAttribute(dataset_id, kChnTypeAttrTitle, type); + GetAttribute(dataset_id, kChnDescAttrTitle, description); H5Dclose(dataset_id); } } - return description; + return CreateInfo(type, description); } -void eCAL::eh5::HDF5MeasFileV2::SetChannelDescription(const std::string& /*channel_name*/, const std::string& /*description*/) +void eCAL::eh5::HDF5MeasFileV2::SetChannelDataTypeInformation(const SChannel& /*channel*/ , const eCAL::eh5::DataTypeInformation& /*info*/) { } -std::string eCAL::eh5::HDF5MeasFileV2::GetChannelType(const std::string& channel_name) const -{ - std::string type; - if (this->IsOk()) - { - auto dataset_id = H5Dopen(file_id_, channel_name.c_str(), H5P_DEFAULT); - if (dataset_id >= 0) - { - GetAttributeValue(dataset_id, kChnTypeAttrTitle, type); - H5Dclose(dataset_id); - } - } - - return type; -} - -void eCAL::eh5::HDF5MeasFileV2::SetChannelType(const std::string& /*channel_name*/, const std::string& /*type*/) -{ -} - -long long eCAL::eh5::HDF5MeasFileV2::GetMinTimestamp(const std::string& channel_name) const +long long eCAL::eh5::HDF5MeasFileV2::GetMinTimestamp(const SChannel& channel) const { long long ret_val = 0; EntryInfoSet entries; - if (GetEntriesInfo(channel_name, entries) && !entries.empty()) + if (GetEntriesInfo(channel, entries) && !entries.empty()) { ret_val = entries.begin()->RcvTimestamp; } @@ -199,12 +182,12 @@ long long eCAL::eh5::HDF5MeasFileV2::GetMinTimestamp(const std::string& channel_ return ret_val; } -long long eCAL::eh5::HDF5MeasFileV2::GetMaxTimestamp(const std::string& channel_name) const +long long eCAL::eh5::HDF5MeasFileV2::GetMaxTimestamp(const SChannel& channel) const { long long ret_val = 0; EntryInfoSet entries; - if (GetEntriesInfo(channel_name, entries) && !entries.empty()) + if (GetEntriesInfo(channel, entries) && !entries.empty()) { ret_val = entries.rbegin()->RcvTimestamp; } @@ -212,13 +195,13 @@ long long eCAL::eh5::HDF5MeasFileV2::GetMaxTimestamp(const std::string& channel_ return ret_val; } -bool eCAL::eh5::HDF5MeasFileV2::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const +bool eCAL::eh5::HDF5MeasFileV2::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const { entries.clear(); if (!this->IsOk()) return false; - auto dataset_id = H5Dopen(file_id_, channel_name.c_str(), H5P_DEFAULT); + auto dataset_id = H5Dopen(file_id_, channel.name.c_str(), H5P_DEFAULT); if (dataset_id < 0) return false; @@ -246,13 +229,13 @@ bool eCAL::eh5::HDF5MeasFileV2::GetEntriesInfo(const std::string& channel_name, return (status >= 0); } -bool eCAL::eh5::HDF5MeasFileV2::GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const +bool eCAL::eh5::HDF5MeasFileV2::GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const { bool ret_val = false; EntryInfoSet all_entries; entries.clear(); - if (GetEntriesInfo(channel_name, all_entries) && !all_entries.empty()) + if (GetEntriesInfo(channel, all_entries) && !all_entries.empty()) { if (begin == 0) begin = entries.begin()->RcvTimestamp; if (end == 0) end = entries.rbegin()->RcvTimestamp; @@ -311,9 +294,9 @@ void eCAL::eh5::HDF5MeasFileV2::SetFileBaseName(const std::string& /*base_name*/ } -bool eCAL::eh5::HDF5MeasFileV2::AddEntryToFile(const void* /*data*/, const unsigned long long& /*size*/, const long long& /*snd_timestamp*/, const long long& /*rcv_timestamp*/, const std::string& /*channel_name*/, long long /*id*/, long long /*clock*/) +bool eCAL::eh5::HDF5MeasFileV2::AddEntryToFile(const SWriteEntry& /*entry*/) { - return false; + return false; } void eCAL::eh5::HDF5MeasFileV2::ConnectPreSplitCallback(CallbackFunction /*cb*/) @@ -322,58 +305,4 @@ void eCAL::eh5::HDF5MeasFileV2::ConnectPreSplitCallback(CallbackFunction /*cb*/) void eCAL::eh5::HDF5MeasFileV2::DisconnectPreSplitCallback() { -} - -bool eCAL::eh5::HDF5MeasFileV2::GetAttributeValue(hid_t obj_id, const std::string& name, std::string& value) -{ - bool ret_val = false; - // empty attribute value - value.clear(); - if (obj_id < 0) return false; - - // check if attribute exists - if (H5Aexists(obj_id, name.c_str()) != 0) - { - // open attribute by name, getting the attribute index - hid_t attr_id = H5Aopen_name(obj_id, name.c_str()); - // fail - attribute can not be opened - if (attr_id <= 0) return false; - - // get attribute type - hid_t attr_type = H5Aget_type(attr_id); - // get type class based on attribute type - H5T_class_t type_class = H5Tget_class(attr_type); - // get attribute content dataSize - const size_t attr_size = H5Tget_size(attr_type); - - // if attribute class is string - if (type_class == H5T_STRING) - { - hid_t attr_type_mem = H5Tget_native_type(attr_type, H5T_DIR_ASCEND); - // create buffer to store the value of the attribute - char* content_buffer = new char[attr_size]; - // get attribute value - ret_val = (H5Aread(attr_id, attr_type_mem, content_buffer) >= 0); - - // convert value to std string - value = std::string(content_buffer, attr_size); - - // free buffer - delete[]content_buffer; - } - else - { - // fail - attribute is not string type - ret_val = false; - } - // close attribute - H5Aclose(attr_id); - } - else - { - // fail - attribute name does not exist - ret_val = false; - } - // return read status - return ret_val; -} +} \ No newline at end of file diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v2.h b/contrib/ecalhdf5/src/eh5_meas_file_v2.h index 6385f4f9fc..17101d59eb 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v2.h +++ b/contrib/ecalhdf5/src/eh5_meas_file_v2.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,7 @@ namespace eCAL * * @param path input file path **/ - explicit HDF5MeasFileV2(const std::string& path, eAccessType access = eAccessType::RDONLY); + explicit HDF5MeasFileV2(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); /** * @brief Destructor @@ -58,7 +58,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool Open(const std::string& path, eAccessType access = eAccessType::RDONLY) override; + bool Open(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY) override; /** * @brief Close file @@ -117,56 +117,40 @@ namespace eCAL */ void SetOneFilePerChannelEnabled(bool enabled) override; - /** - * @brief Get the available channel names of the current opened file / measurement - * - * @return channel names + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids **/ - std::set GetChannelNames() const override; + std::set GetChannels() const override; /** - * @brief Check if channel exists in measurement - * - * @param channel_name name of the channel - * - * @return true if exists, false otherwise + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise **/ - bool HasChannel(const std::string& channel_name) const override; + bool HasChannel(const eCAL::eh5::SChannel& channel) const override; /** - * @brief Get the channel description for the given channel - * - * @param channel_name channel name - * - * @return channel description + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type **/ - std::string GetChannelDescription(const std::string& channel_name) const override; + DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const override; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type **/ - void SetChannelDescription(const std::string& channel_name, const std::string& description) override; - - /** - * @brief Gets the channel type of the given channel - * - * @param channel_name channel name - * - * @return channel type - **/ - std::string GetChannelType(const std::string& channel_name) const override; - - /** - * @brief Set type of the given channel - * - * @param channel_name channel name - * @param type type of the channel - **/ - void SetChannelType(const std::string& channel_name, const std::string& type) override; + void SetChannelDataTypeInformation(const SChannel& channel, const DataTypeInformation& info) override; /** * @brief Gets minimum timestamp for specified channel @@ -175,7 +159,7 @@ namespace eCAL * * @return minimum timestamp value **/ - long long GetMinTimestamp(const std::string& channel_name) const override; + long long GetMinTimestamp(const SChannel& channel) const override; /** * @brief Gets maximum timestamp for specified channel @@ -184,7 +168,7 @@ namespace eCAL * * @return maximum timestamp value **/ - long long GetMaxTimestamp(const std::string& channel_name) const override; + long long GetMaxTimestamp(const SChannel& channel) const override; /** * @brief Gets the header info for all data entries for the given channel @@ -195,7 +179,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) @@ -208,7 +192,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const override; + bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const override; /** * @brief Gets data size of a specific entry @@ -250,7 +234,8 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) override; + bool AddEntryToFile(const SWriteEntry& entry) override; + typedef std::function CallbackFunction; /** @@ -267,17 +252,6 @@ namespace eCAL protected: hid_t file_id_; - - /** - * @brief Gets the value of a string attribute - * - * @param [in] obj_id ID of the attribute's parent - * @param [in] name Name of the attribute - * @param [out] value Value of the attribute - * - * @return true if succeeds, false if it fails - **/ - static bool GetAttributeValue(hid_t obj_id, const std::string& name, std::string& value) ; }; } // namespace eh5 diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v3.cpp b/contrib/ecalhdf5/src/eh5_meas_file_v3.cpp index 0469d80619..36e5eec07f 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v3.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_file_v3.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ namespace eCAL namespace eh5 { - HDF5MeasFileV3::HDF5MeasFileV3(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) + HDF5MeasFileV3::HDF5MeasFileV3(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) : HDF5MeasFileV2(path, access) { } @@ -41,13 +41,13 @@ namespace eCAL HDF5MeasFileV3::~HDF5MeasFileV3() = default; - bool HDF5MeasFileV3::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const + bool HDF5MeasFileV3::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const { entries.clear(); if (!this->IsOk()) return false; - hid_t dataset_id = H5Dopen(file_id_, channel_name.c_str(), H5P_DEFAULT); + hid_t dataset_id = H5Dopen(file_id_, channel.name.c_str(), H5P_DEFAULT); if (dataset_id < 0) return false; diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v3.h b/contrib/ecalhdf5/src/eh5_meas_file_v3.h index 716bf00a7c..3c16b5ff32 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v3.h +++ b/contrib/ecalhdf5/src/eh5_meas_file_v3.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ namespace eCAL * * @param path Input file path **/ - explicit HDF5MeasFileV3(const std::string& path, eAccessType access = eAccessType::RDONLY); + explicit HDF5MeasFileV3(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); /** * @brief Destructor @@ -60,7 +60,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; }; } // namespace eh5 } // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v4.cpp b/contrib/ecalhdf5/src/eh5_meas_file_v4.cpp index ae5d125d76..dd33c70497 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v4.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_file_v4.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ namespace eCAL namespace eh5 { - HDF5MeasFileV4::HDF5MeasFileV4(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) + HDF5MeasFileV4::HDF5MeasFileV4(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) : HDF5MeasFileV2(path, access) { } @@ -41,13 +41,13 @@ namespace eCAL HDF5MeasFileV4::~HDF5MeasFileV4() = default; - bool HDF5MeasFileV4::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const + bool HDF5MeasFileV4::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const { entries.clear(); if (!this->IsOk()) return false; - auto dataset_id = H5Dopen(file_id_, channel_name.c_str(), H5P_DEFAULT); + auto dataset_id = H5Dopen(file_id_, channel.name.c_str(), H5P_DEFAULT); if (dataset_id < 0) return false; diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v4.h b/contrib/ecalhdf5/src/eh5_meas_file_v4.h index f9d1139752..d2b0de9737 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v4.h +++ b/contrib/ecalhdf5/src/eh5_meas_file_v4.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ namespace eCAL * * @param path Input file path **/ - explicit HDF5MeasFileV4(const std::string& path, eAccessType access = eAccessType::RDONLY); + explicit HDF5MeasFileV4(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); /** * @brief Destructor @@ -60,7 +60,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; }; } // namespace eh5 } // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v5.cpp b/contrib/ecalhdf5/src/eh5_meas_file_v5.cpp index 39960e6015..5ba1eebb8a 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v5.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_file_v5.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ namespace eCAL namespace eh5 { - HDF5MeasFileV5::HDF5MeasFileV5(const std::string& path, eAccessType access /*= eAccessType::RDONLY*/) + HDF5MeasFileV5::HDF5MeasFileV5(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) : HDF5MeasFileV2(path, access) { } @@ -41,13 +41,13 @@ namespace eCAL HDF5MeasFileV5::~HDF5MeasFileV5() = default; - bool HDF5MeasFileV5::GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const + bool HDF5MeasFileV5::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const { entries.clear(); if (!this->IsOk()) return false; - auto dataset_id = H5Dopen(file_id_, channel_name.c_str(), H5P_DEFAULT); + auto dataset_id = H5Dopen(file_id_, channel.name.c_str(), H5P_DEFAULT); if (dataset_id < 0) return false; diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v5.h b/contrib/ecalhdf5/src/eh5_meas_file_v5.h index 9188616b15..ec2d7acc28 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_v5.h +++ b/contrib/ecalhdf5/src/eh5_meas_file_v5.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ namespace eCAL * * @param path Input file path **/ - explicit HDF5MeasFileV5(const std::string& path, eAccessType access = eAccessType::RDONLY); + explicit HDF5MeasFileV5(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); /** * @brief Destructor @@ -60,7 +60,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; }; } // namespace eh5 } // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v6.cpp b/contrib/ecalhdf5/src/eh5_meas_file_v6.cpp new file mode 100644 index 0000000000..3aa8e5058a --- /dev/null +++ b/contrib/ecalhdf5/src/eh5_meas_file_v6.cpp @@ -0,0 +1,128 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief eCALHDF5 reader multiple channels implement +**/ + +#include "eh5_meas_file_v6.h" + +#include "hdf5.h" +#include "hdf5_helper.h" + +namespace eCAL +{ + namespace eh5 + { + + HDF5MeasFileV6::HDF5MeasFileV6(const std::string& path, v3::eAccessType access /*= eAccessType::RDONLY*/) + : HDF5MeasFileV2(path, access) + { + } + + HDF5MeasFileV6::HDF5MeasFileV6() + = default; + + HDF5MeasFileV6::~HDF5MeasFileV6() + = default; + + // Channels have to be obtained differently, the names themselves are written in the header + // for channel, id, we need to traverse the file format and get them. + std::set HDF5MeasFileV6::GetChannels() const + { + std::set channels; + // V2 Channel function will return (channel_name, 0) + // so we will take those channel_names + const auto channels_v2 = HDF5MeasFileV2::GetChannels(); + + for (const auto& channel_v2 : channels_v2) + { + const auto& channel_name = channel_v2.name; + auto group_id = H5Gopen(file_id_, channel_name.c_str(), H5P_DEFAULT); + auto groups = ListSubgroups(group_id); + H5Gclose(group_id); + + for (const auto& group : groups) + { + const auto id = parseHexID(group); + channels.insert({ channel_name, id }); + } + + } + + return channels; + } + + bool HDF5MeasFileV6::HasChannel(const eCAL::eh5::SChannel& channel) const + { + bool has_channel_name = HasGroup(file_id_, channel.name); + if (!has_channel_name) + { + return false; + } + auto group_id = H5Gopen(file_id_, channel.name.c_str(), H5P_DEFAULT); + bool has_channel_id = HasGroup(group_id, printHex(channel.id).c_str()); + H5Gclose(group_id); + + return has_channel_id; + } + + eCAL::eh5::DataTypeInformation eCAL::eh5::HDF5MeasFileV6::GetChannelDataTypeInformation(const SChannel& channel) const + { + std::string type_name; + std::string type_encoding; + std::string type_descriptor; + + auto group_id = H5Gopen(file_id_, channel.name.c_str(), H5P_DEFAULT); + auto groups = ListSubgroups(group_id); + H5Gclose(group_id); + + if (this->IsOk()) + { + std::string channel_id_key = printHex(channel.id); + + // Read Typename + auto type_name_url = v6::GetUrl(channel.name, channel_id_key, eCAL::eh5::kChnIdTypename); + ReadStringEntryAsString(file_id_, type_name_url, type_name); + + // Read Encoding + auto type_encoding_url = v6::GetUrl(channel.name, channel_id_key, eCAL::eh5::kChnIdEncoding); + ReadStringEntryAsString(file_id_, type_encoding_url, type_encoding); + + // Read Descriptor + auto type_descriptor_url = v6::GetUrl(channel.name, channel_id_key, eCAL::eh5::kChnIdDescriptor); + ReadStringEntryAsString(file_id_, type_descriptor_url, type_descriptor); + } + + return eCAL::eh5::DataTypeInformation{ type_name, type_encoding, type_descriptor }; + } + + bool eCAL::eh5::HDF5MeasFileV6::GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const + { + if (!this->IsOk()) return false; + + auto hex_id = printHex(channel.id); + EntryInfoSet channel_id_entries; + auto url = v6::GetUrl(channel.name, hex_id, kChnIdData); + GetEntryInfoVector(file_id_, url, entries); + + return true; + } + } // namespace eh5 +} // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_file_v6.h b/contrib/ecalhdf5/src/eh5_meas_file_v6.h new file mode 100644 index 0000000000..536e7cd0aa --- /dev/null +++ b/contrib/ecalhdf5/src/eh5_meas_file_v6.h @@ -0,0 +1,75 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * eCALHDF5 file reader multiple channels +**/ + +#pragma once + +#include + +#include "eh5_meas_file_v5.h" + +namespace eCAL +{ + namespace eh5 + { + class HDF5MeasFileV6 : virtual public HDF5MeasFileV5 + { + public: + /** + * @brief Constructor + **/ + HDF5MeasFileV6(); + + /** + * @brief Constructor + * + * @param path Input file path + **/ + explicit HDF5MeasFileV6(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY); + + /** + * @brief Destructor + **/ + ~HDF5MeasFileV6() override; + + /** + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids + **/ + std::set GetChannels() const override; + + /** + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise + **/ + bool HasChannel(const eCAL::eh5::SChannel& channel) const override; + + DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const override; + + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; + }; + } // namespace eh5 +} // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.cpp b/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.cpp index b96d8396b9..7d0562d275 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.cpp +++ b/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ #include "eh5_meas_file_writer_v5.h" #include "escape.h" +#include "datatype_helper.h" #ifdef WIN32 #include @@ -54,7 +55,7 @@ eCAL::eh5::HDF5MeasFileWriterV5::~HDF5MeasFileWriterV5() HDF5MeasFileWriterV5::Close(); } -bool eCAL::eh5::HDF5MeasFileWriterV5::Open(const std::string& output_dir, eAccessType /*access = eAccessType::RDONLY*/) +bool eCAL::eh5::HDF5MeasFileWriterV5::Open(const std::string& output_dir, v3::eAccessType /*access = eAccessType::RDONLY*/) { Close(); @@ -126,59 +127,50 @@ void eCAL::eh5::HDF5MeasFileWriterV5::SetOneFilePerChannelEnabled(bool /*enabled { } -std::set eCAL::eh5::HDF5MeasFileWriterV5::GetChannelNames() const +std::set eCAL::eh5::HDF5MeasFileWriterV5::GetChannels() const { - // UNSUPPORTED FUNCTION - return {}; + // UNSUPPORTED FUNCTIONs + return std::set(); } -bool eCAL::eh5::HDF5MeasFileWriterV5::HasChannel(const std::string& /*channel_name*/) const +bool eCAL::eh5::HDF5MeasFileWriterV5::HasChannel(const eCAL::eh5::SChannel& /*channel*/ ) const { // UNSUPPORTED FUNCTION return false; } -std::string eCAL::eh5::HDF5MeasFileWriterV5::GetChannelDescription(const std::string& /*channel_name*/) const -{ - // UNSUPPORTED FUNCTION - return ""; -} - -void eCAL::eh5::HDF5MeasFileWriterV5::SetChannelDescription(const std::string& channel_name, const std::string& description) -{ - channels_[channel_name].Description = description; -} - -std::string eCAL::eh5::HDF5MeasFileWriterV5::GetChannelType(const std::string& /*channel_name*/) const +eCAL::eh5::DataTypeInformation eCAL::eh5::HDF5MeasFileWriterV5::GetChannelDataTypeInformation(const SChannel& /*channel*/) const { // UNSUPPORTED FUNCTION - return ""; + return eCAL::eh5::DataTypeInformation{}; } -void eCAL::eh5::HDF5MeasFileWriterV5::SetChannelType(const std::string& channel_name, const std::string& type) +void eCAL::eh5::HDF5MeasFileWriterV5::SetChannelDataTypeInformation(const SChannel& channel, const eCAL::eh5::DataTypeInformation& info) { - channels_[channel_name].Type = type; + auto type_descriptor = FromInfo(info); + channels_[channel.name].Type = type_descriptor.first; + channels_[channel.name].Description = type_descriptor.second; } -long long eCAL::eh5::HDF5MeasFileWriterV5::GetMinTimestamp(const std::string& /*channel_name*/) const +long long eCAL::eh5::HDF5MeasFileWriterV5::GetMinTimestamp(const SChannel& /*channel*/) const { // UNSUPPORTED FUNCTION return -1; } -long long eCAL::eh5::HDF5MeasFileWriterV5::GetMaxTimestamp(const std::string& /*channel_name*/) const +long long eCAL::eh5::HDF5MeasFileWriterV5::GetMaxTimestamp(const SChannel& /*channel*/) const { // UNSUPPORTED FUNCTION return -1; } -bool eCAL::eh5::HDF5MeasFileWriterV5::GetEntriesInfo(const std::string& /*channel_name*/, EntryInfoSet& /*entries*/) const +bool eCAL::eh5::HDF5MeasFileWriterV5::GetEntriesInfo(const SChannel& /*channel*/, EntryInfoSet& /*entries*/) const { // UNSUPPORTED FUNCTION return false; } -bool eCAL::eh5::HDF5MeasFileWriterV5::GetEntriesInfoRange(const std::string& /*channel_name*/, long long /*begin*/, long long /*end*/, EntryInfoSet& /*entries*/) const +bool eCAL::eh5::HDF5MeasFileWriterV5::GetEntriesInfoRange(const SChannel& /*channel*/, long long /*begin*/, long long /*end*/, EntryInfoSet& /*entries*/) const { // UNSUPPORTED FUNCTION return false; @@ -201,13 +193,13 @@ void eCAL::eh5::HDF5MeasFileWriterV5::SetFileBaseName(const std::string& base_na base_name_ = base_name; } -bool eCAL::eh5::HDF5MeasFileWriterV5::AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) +bool eCAL::eh5::HDF5MeasFileWriterV5::AddEntryToFile(const SWriteEntry& entry) { if (!IsOk()) file_id_ = Create(); if (!IsOk()) return false; - hsize_t hsSize = static_cast(size); + hsize_t hsSize = static_cast(entry.size); if (!EntryFitsTheFile(hsSize)) { @@ -231,14 +223,14 @@ bool eCAL::eh5::HDF5MeasFileWriterV5::AddEntryToFile(const void* data, const uns auto dataSet = H5Dcreate(file_id_, std::to_string(entries_counter_).c_str(), H5T_NATIVE_UCHAR, dataSpace, H5P_DEFAULT, dsProperty, H5P_DEFAULT); // Write buffer to dataset - herr_t writeStatus = H5Dwrite(dataSet, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, data); + herr_t writeStatus = H5Dwrite(dataSet, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, entry.data); // Close dataset, data space, and data set property H5Dclose(dataSet); H5Pclose(dsProperty); H5Sclose(dataSpace); - channels_[channel_name].Entries.emplace_back(SEntryInfo(rcv_timestamp, static_cast(entries_counter_), clock, snd_timestamp, id)); + channels_[entry.channel.name].Entries.emplace_back(SEntryInfo(entry.rcv_timestamp, static_cast(entries_counter_), entry.clock, entry.snd_timestamp, entry.sender_id)); entries_counter_++; diff --git a/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.h b/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.h index 0b10238c41..975d1f34b4 100644 --- a/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.h +++ b/contrib/ecalhdf5/src/eh5_meas_file_writer_v5.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -65,7 +65,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool Open(const std::string& output_dir, eAccessType access) override; + bool Open(const std::string& output_dir, v3::eAccessType access) override; /** * @brief Close file @@ -125,54 +125,39 @@ namespace eCAL void SetOneFilePerChannelEnabled(bool enabled) override; /** - * @brief Get the available channel names of the current opened file / measurement - * - * @return channel names - **/ - std::set GetChannelNames() const override; - - /** - * @brief Check if channel exists in measurement - * - * @param channel_name name of the channel - * - * @return true if exists, false otherwise - **/ - bool HasChannel(const std::string& channel_name) const override; - - /** - * @brief Get the channel description for the given channel - * - * @param channel_name channel name - * - * @return channel description + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids **/ - std::string GetChannelDescription(const std::string& channel_name) const override; + std::set GetChannels() const override; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise **/ - void SetChannelDescription(const std::string& channel_name, const std::string& description) override; + bool HasChannel(const eCAL::eh5::SChannel & channel) const override; /** - * @brief Gets the channel type of the given channel - * - * @param channel_name channel name - * - * @return channel type + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type **/ - std::string GetChannelType(const std::string& channel_name) const override; + DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const override; /** - * @brief Set type of the given channel - * - * @param channel_name channel name - * @param type type of the channel + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type **/ - void SetChannelType(const std::string& channel_name, const std::string& type) override; + void SetChannelDataTypeInformation(const SChannel& channel, const DataTypeInformation & info) override; /** * @brief Gets minimum timestamp for specified channel @@ -181,7 +166,7 @@ namespace eCAL * * @return minimum timestamp value **/ - long long GetMinTimestamp(const std::string& channel_name) const override; + long long GetMinTimestamp(const SChannel& channel) const override; /** * @brief Gets maximum timestamp for specified channel @@ -190,7 +175,7 @@ namespace eCAL * * @return maximum timestamp value **/ - long long GetMaxTimestamp(const std::string& channel_name) const override; + long long GetMaxTimestamp(const SChannel& channel) const override; /** * @brief Gets the header info for all data entries for the given channel @@ -201,7 +186,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const override; + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) @@ -214,7 +199,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const override; + bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const override; /** * @brief Gets data size of a specific entry @@ -256,7 +241,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) override; + bool AddEntryToFile(const SWriteEntry& entry) override; using CallbackFunction = std::function; /** diff --git a/contrib/ecalhdf5/src/eh5_meas_file_writer_v6.cpp b/contrib/ecalhdf5/src/eh5_meas_file_writer_v6.cpp new file mode 100644 index 0000000000..4689073a97 --- /dev/null +++ b/contrib/ecalhdf5/src/eh5_meas_file_writer_v6.cpp @@ -0,0 +1,339 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief eCALHDF5 directory reader +**/ + +#include "eh5_meas_file_writer_v6.h" +#include "escape.h" + +#ifdef WIN32 +#include +#else +#include +#endif //WIN32 + +#include +#include +#include + +#include +#include + +#include "hdf5_helper.h" + +constexpr unsigned int kDefaultMaxFileSizeMB = 1000; + +eCAL::eh5::HDF5MeasFileWriterV6::HDF5MeasFileWriterV6() + : cb_pre_split_ (nullptr) + , file_id_ (-1) + , file_split_counter_(-1) + , entries_counter_ (0) + , max_size_per_file_ (kDefaultMaxFileSizeMB * 1024 * 1024) +{} + +eCAL::eh5::HDF5MeasFileWriterV6::~HDF5MeasFileWriterV6() +{ + // call the function via its class becase it's a virtual function that is called in constructor/destructor,- + // where the vtable is not created yet or it's destructed. + HDF5MeasFileWriterV6::Close(); +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::Open(const std::string& output_dir, v3::eAccessType /*access = eAccessType::RDONLY*/) +{ + Close(); + + // Check if the given path points to a directory + if (!EcalUtils::Filesystem::IsDir(output_dir, EcalUtils::Filesystem::Current)) + return false; + + output_dir_ = output_dir; + + return true; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::Close() +{ + if (!this->IsOk()) return false; + + std::string channels_with_entries; + + for (const auto& channel_per_name : channels_) + { + for (const auto& channel_per_id : channel_per_name.second) + { + std::ignore = CreateEntriesTableOfContentsFor(channel_per_name.first, channel_per_id.first, channel_per_id.second.Info, channel_per_id.second.Entries); + } + channels_with_entries += channel_per_name.first + ","; + } + + if ((!channels_with_entries.empty()) && (channels_with_entries.back() == ',')) + channels_with_entries.pop_back(); + + SetAttribute(file_id_, kChnAttrTitle, channels_with_entries); + + for (auto& channel_per_name : channels_) + for (auto& channel_per_id : channel_per_name.second) + channel_per_id.second.Entries.clear(); + + if (H5Fclose(file_id_) >= 0) + { + file_id_ = -1; + return true ; + } + else + { + return false; + } +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::IsOk() const +{ + return (file_id_ >= 0); +} + +std::string eCAL::eh5::HDF5MeasFileWriterV6::GetFileVersion() const +{ + // UNSUPPORTED FUNCTION + return ""; +} + +size_t eCAL::eh5::HDF5MeasFileWriterV6::GetMaxSizePerFile() const +{ + return max_size_per_file_ / 1024 / 1024; +} + +void eCAL::eh5::HDF5MeasFileWriterV6::SetMaxSizePerFile(size_t max_file_size_mib) +{ + max_size_per_file_ = max_file_size_mib * 1024 * 1024; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::IsOneFilePerChannelEnabled() const +{ + return false; +} + +void eCAL::eh5::HDF5MeasFileWriterV6::SetOneFilePerChannelEnabled(bool /*enabled*/) +{ +} + +std::set eCAL::eh5::HDF5MeasFileWriterV6::GetChannels() const +{ + // UNSUPPORTED FUNCTION + return std::set(); +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::HasChannel(const eCAL::eh5::SChannel& /*channel*/) const +{ + // UNSUPPORTED FUNCTION + return false; +} + +eCAL::eh5::DataTypeInformation eCAL::eh5::HDF5MeasFileWriterV6::GetChannelDataTypeInformation(const SChannel& /*channel*/) const +{ + // UNSUPPORTED FUNCTION + return eCAL::eh5::DataTypeInformation{}; +} + +void eCAL::eh5::HDF5MeasFileWriterV6::SetChannelDataTypeInformation(const SChannel& channel , const eCAL::eh5::DataTypeInformation& info) +{ + channels_[channel.name][channel.id].Info = info; +} + + +long long eCAL::eh5::HDF5MeasFileWriterV6::GetMinTimestamp(const SChannel& /*channel_name*/) const +{ + // UNSUPPORTED FUNCTION + return -1; +} + +long long eCAL::eh5::HDF5MeasFileWriterV6::GetMaxTimestamp(const SChannel& /*channel_name*/) const +{ + // UNSUPPORTED FUNCTION + return -1; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::GetEntriesInfo(const SChannel& /*channel_name*/, EntryInfoSet& /*entries*/) const +{ + // UNSUPPORTED FUNCTION + return false; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::GetEntriesInfoRange(const SChannel& /*channel_name*/, long long /*begin*/, long long /*end*/, EntryInfoSet& /*entries*/) const +{ + // UNSUPPORTED FUNCTION + return false; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::GetEntryDataSize(long long /*entry_id*/, size_t& /*size*/) const +{ + // UNSUPPORTED FUNCTION + return false; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::GetEntryData(long long /*entry_id*/, void* /*data*/) const +{ + // UNSUPPORTED FUNCTION + return false; +} + +void eCAL::eh5::HDF5MeasFileWriterV6::SetFileBaseName(const std::string& base_name) +{ + base_name_ = base_name; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::AddEntryToFile(const SWriteEntry& entry) +{ + if (!IsOk()) file_id_ = Create(); + if (!IsOk()) + return false; + + hsize_t hsSize = static_cast(entry.size); + + if (!EntryFitsTheFile(hsSize)) + { + if (cb_pre_split_ != nullptr) + { + cb_pre_split_(); + } + + if (Create() < 0) + return false; + } + + // Create DataSpace with rank 1 and size dimension + auto dataSpace = H5Screate_simple(1, &hsSize, nullptr); + + // Create creation property for dataSpace + auto dsProperty = H5Pcreate(H5P_DATASET_CREATE); + H5Pset_obj_track_times(dsProperty, false); + + // Create dataset in dataSpace + auto dataSet = H5Dcreate(file_id_, std::to_string(entries_counter_).c_str(), H5T_NATIVE_UCHAR, dataSpace, H5P_DEFAULT, dsProperty, H5P_DEFAULT); + + // Write buffer to dataset + herr_t writeStatus = H5Dwrite(dataSet, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, entry.data); + + // Close dataset, data space, and data set property + H5Dclose(dataSet); + H5Pclose(dsProperty); + H5Sclose(dataSpace); + + // TODO: check here about id vs channel.id + channels_[entry.channel.name][entry.channel.id].Entries.emplace_back(SEntryInfo(entry.rcv_timestamp, static_cast(entries_counter_), entry.clock, entry.snd_timestamp, entry.sender_id)); + + entries_counter_++; + + return (writeStatus >= 0); +} + +void eCAL::eh5::HDF5MeasFileWriterV6::ConnectPreSplitCallback(CallbackFunction cb) +{ + cb_pre_split_ = cb; +} + +void eCAL::eh5::HDF5MeasFileWriterV6::DisconnectPreSplitCallback() +{ + cb_pre_split_ = nullptr; +} + +hid_t eCAL::eh5::HDF5MeasFileWriterV6::Create() +{ + if (output_dir_.empty()) return -1; + + if (!EcalUtils::Filesystem::IsDir(output_dir_, EcalUtils::Filesystem::OsStyle::Current) + && !EcalUtils::Filesystem::MkPath(output_dir_, EcalUtils::Filesystem::OsStyle::Current)) + return -1; + + if (base_name_.empty()) return -1; + + if (IsOk() && !Close()) return -1; + + file_split_counter_++; + + std::string filePath = output_dir_ + "/" + base_name_; + + if (file_split_counter_ > 0) + filePath += "_" + std::to_string(file_split_counter_); + + filePath += ".hdf5"; + + // create file access property + hid_t fileAccessPropery = H5Pcreate(H5P_FILE_ACCESS); + // create file create property + hid_t fileCreateProperty = H5Pcreate(H5P_FILE_CREATE); + + // Create hdf file and get file id + file_id_ = H5Fcreate(filePath.c_str(), H5F_ACC_TRUNC, fileCreateProperty, fileAccessPropery); + + if (file_id_ >= 0) + SetAttribute(file_id_, kFileVerAttrTitle, "6.0"); + else + file_split_counter_--; + + return file_id_; +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::EntryFitsTheFile(const hsize_t& size) const +{ + hsize_t fileSize = 0; + bool status = GetFileSize(fileSize); + + // check if buffer fits the current file + return (status && ((fileSize + size) <= max_size_per_file_)); +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::GetFileSize(hsize_t& size) const +{ + if (!IsOk()) + { + size = 0; + return false; + } + else + { + return H5Fget_filesize(file_id_, &size) >= 0; + } +} + +bool eCAL::eh5::HDF5MeasFileWriterV6::CreateEntriesTableOfContentsFor(const std::string& channelName, std::uint64_t channelId, const DataTypeInformation& channelInfo, const EntryInfoVect& entries) const +{ + if (!IsOk()) return false; + +// const size_t dataSetsSize = entries.size(); +// if (dataSetsSize == 0) return false; + + std::string hex_id = printHex(channelId); + + // Create a group with the cannel name + auto group_name_id = OpenOrCreateGroup(file_id_, channelName); + auto group_id_id = OpenOrCreateGroup(group_name_id, hex_id); + + CreateStringEntryInRoot(file_id_, v6::GetUrl(channelName, hex_id, kChnIdTypename), channelInfo.name); + CreateStringEntryInRoot(file_id_, v6::GetUrl(channelName, hex_id, kChnIdEncoding), channelInfo.encoding); + CreateStringEntryInRoot(file_id_, v6::GetUrl(channelName, hex_id, kChnIdDescriptor), channelInfo.descriptor); + CreateInformationEntryInRoot(file_id_, v6::GetUrl(channelName, hex_id, kChnIdData), entries); + + H5Gclose(group_name_id); + H5Gclose(group_id_id); + + return true; +} + diff --git a/contrib/ecalhdf5/src/eh5_meas_file_writer_v6.h b/contrib/ecalhdf5/src/eh5_meas_file_writer_v6.h new file mode 100644 index 0000000000..8ff05339c0 --- /dev/null +++ b/contrib/ecalhdf5/src/eh5_meas_file_writer_v6.h @@ -0,0 +1,318 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * eCALHDF5 file reader single channel +**/ + +#pragma once + +#include +#include +#include +#include + +#include "eh5_meas_impl.h" + +#include "hdf5.h" + +namespace eCAL +{ + namespace eh5 + { + class HDF5MeasFileWriterV6 : virtual public HDF5MeasImpl + { + public: + /** + * @brief Constructor + **/ + HDF5MeasFileWriterV6(); + + // Copy + HDF5MeasFileWriterV6(const HDF5MeasFileWriterV6&) = delete; + HDF5MeasFileWriterV6& operator=(const HDF5MeasFileWriterV6&) = delete; + + // Move + HDF5MeasFileWriterV6& operator=(HDF5MeasFileWriterV6&&) = default; + HDF5MeasFileWriterV6(HDF5MeasFileWriterV6&&) = default; + + /** + * @brief Destructor + **/ + ~HDF5MeasFileWriterV6() override; + + /** + * @brief Open file + * + * @param output_dir Input file path / measurement directory path + * @param access Access type (IGNORED, WILL ALWAYS OPEN READ-WRITE!) + * + * @return true if succeeds, false if it fails + **/ + bool Open(const std::string& output_dir, v3::eAccessType access) override; + + /** + * @brief Close file + * + * @return true if succeeds, false if it fails + **/ + bool Close() override; + + /** + * @brief Checks if file/measurement is ok + * + * @return true if meas can be opened(read) or location is accessible(write), false otherwise + **/ + bool IsOk() const override; + + /** + * @brief Get the File Type Version of the current opened file + * + * @return file version + **/ + std::string GetFileVersion() const override; + + /** + * @brief Gets maximum allowed size for an individual file + * + * @return maximum size in MB + **/ + size_t GetMaxSizePerFile() const override; + + /** + * @brief Sets maximum allowed size for an individual file + * + * @param max_file_size_mib maximum size in MB + **/ + void SetMaxSizePerFile(size_t max_file_size_mib) override; + + /** + * @brief Whether each Channel shall be writte in its own file + * + * When enabled, data is clustered by channel and each channel is written + * to its own file. The filenames will consist of the basename and the + * channel name. + * + * @return true, if one file per channel is enabled + */ + bool IsOneFilePerChannelEnabled() const override; + + /** + * @brief Enable / disable the creation of one individual file per channel + * + * When enabled, data is clustered by channel and each channel is written + * to its own file. The filenames will consist of the basename and the + * channel name. + * + * @param enabled Whether one file shall be created per channel + */ + void SetOneFilePerChannelEnabled(bool enabled) override; + + /** + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids + **/ + std::set GetChannels() const override; + + /** + * @brief Check if channel exists in measurement + * + * @param channel channel name & id + * + * @return true if exists, false otherwise + **/ + bool HasChannel(const eCAL::eh5::SChannel & channel) const override; + + /** + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type + **/ + DataTypeInformation GetChannelDataTypeInformation(const SChannel & channel) const override; + + /** + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type + **/ + void SetChannelDataTypeInformation(const SChannel& channel, const eCAL::eh5::DataTypeInformation& info) override; + + /** + * @brief Gets minimum timestamp for specified channel + * + * @param channel_name channel name + * + * @return minimum timestamp value + **/ + long long GetMinTimestamp(const SChannel& channel) const override; + + /** + * @brief Gets maximum timestamp for specified channel + * + * @param channel_name channel name + * + * @return maximum timestamp value + **/ + long long GetMaxTimestamp(const SChannel& channele) const override; + + /** + * @brief Gets the header info for all data entries for the given channel + * Header = timestamp + entry id + * + * @param [in] channel_name channel name + * @param [out] entries header info for all data entries + * + * @return true if succeeds, false if it fails + **/ + bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const override; + + /** + * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) + * Header = timestamp + entry id + * + * @param [in] channel_name channel name + * @param [in] begin time range begin timestamp + * @param [in] end time range end timestamp + * @param [out] entries header info for data entries in given range + * + * @return true if succeeds, false if it fails + **/ + bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const override; + + /** + * @brief Gets data size of a specific entry + * + * @param [in] entry_id Entry ID + * @param [out] size Entry data size + * + * @return true if succeeds, false if it fails + **/ + bool GetEntryDataSize(long long entry_id, size_t& size) const override; + + /** + * @brief Gets data from a specific entry + * + * @param [in] entry_id Entry ID + * @param [out] data Entry data + * + * @return true if succeeds, false if it fails + **/ + bool GetEntryData(long long entry_id, void* data) const override; + + /** + * @brief Set measurement file base name + * + * @param base_name File base name. + **/ + void SetFileBaseName(const std::string& base_name) override; + + /** + * @brief Add entry to file + * + * @param data data to be added + * @param size size of the data + * @param snd_timestamp send timestamp + * @param rcv_timestamp receive timestamp + * @param channel channel name + * @param id message id + * @param clock message clock + * + * @return true if succeeds, false if it fails + **/ + bool AddEntryToFile(const SWriteEntry& entry) override; + + using CallbackFunction = std::function; + /** + * @brief Connect callback for pre file split notification + * + * @param cb callback function + **/ + void ConnectPreSplitCallback(CallbackFunction cb) override; + + /** + * @brief Disconnect pre file split callback + **/ + void DisconnectPreSplitCallback() override; + + protected: + struct Channel + { + DataTypeInformation Info; + EntryInfoVect Entries; + }; + + using Channels = std::map>; + + std::string output_dir_; + std::string base_name_; + Channels channels_; + CallbackFunction cb_pre_split_; + hid_t file_id_; + int file_split_counter_; + unsigned long long entries_counter_; + size_t max_size_per_file_; + + /** + * @brief Creates the actual file + * + * @return file ID, file was not created if id is negative + **/ + hid_t Create(); + + /** + * @brief Checks if current file size + entry size does not exceed the maximum allowed size of the file + * + * @param size Size of the entry in bytes + * + * @return true if entry can be saved in current file, false if it can not be added to the current file + **/ + bool EntryFitsTheFile(const hsize_t& size) const; + + /** + * @brief Gets the size of the file + * + * @param size Size of the file in bytes + * + * @return true if succeeds, false if it fails + **/ + bool GetFileSize(hsize_t& size) const; + + /** + * @brief Creates the entries "table of contents" (timestamp + entry id) + * (Call it just before closing the file) + * + * @param channelName name for the dataset + * @param channelId id for the dataset (unique publisher ID) + * @param channelType type for the dataset + * @param channelDescription description for the dataset + * @param entries entries for given channel + * + * @return true if succeeds, false if it fails + **/ + bool CreateEntriesTableOfContentsFor(const std::string& channelName, std::uint64_t channelId, const DataTypeInformation& channelInfo, const EntryInfoVect& entries) const; + + }; + } // namespace eh5 +} // namespace eCAL diff --git a/contrib/ecalhdf5/src/eh5_meas_impl.h b/contrib/ecalhdf5/src/eh5_meas_impl.h index e1825b5103..97cc4fa563 100644 --- a/contrib/ecalhdf5/src/eh5_meas_impl.h +++ b/contrib/ecalhdf5/src/eh5_meas_impl.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,7 +49,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - virtual bool Open(const std::string& path, eAccessType access = eAccessType::RDONLY) = 0; + virtual bool Open(const std::string& path, v3::eAccessType access = v3::eAccessType::RDONLY) = 0; /** * @brief Close file @@ -108,56 +108,40 @@ namespace eCAL */ virtual void SetOneFilePerChannelEnabled(bool enabled) = 0; - /** - * @brief Get the available channel names of the current opened file / measurement - * - * @return channel names + * @brief Get the available channel names of the current opened file / measurement + * + * @return channel names & ids **/ - virtual std::set GetChannelNames() const = 0; + virtual std::set GetChannels() const = 0; /** * @brief Check if channel exists in measurement * - * @param channel_name name of the channel + * @param channel channel name & id * * @return true if exists, false otherwise **/ - virtual bool HasChannel(const std::string& channel_name) const = 0; + virtual bool HasChannel(const eCAL::eh5::SChannel& channel) const = 0; /** - * @brief Get the channel description for the given channel - * - * @param channel_name channel name - * - * @return channel description + * @brief Get data type information of the given channel + * + * @param channel_name channel name + * + * @return channel type **/ - virtual std::string GetChannelDescription(const std::string& channel_name) const = 0; + virtual DataTypeInformation GetChannelDataTypeInformation(const SChannel& channel) const = 0; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel - **/ - virtual void SetChannelDescription(const std::string& channel_name, const std::string& description) = 0; - - /** - * @brief Gets the channel type of the given channel - * - * @param channel_name channel name - * - * @return channel type - **/ - virtual std::string GetChannelType(const std::string& channel_name) const = 0; - - /** - * @brief Set type of the given channel - * - * @param channel_name channel name - * @param type type of the channel + * @brief Set data type information of the given channel + * + * @param channel_name channel name + * @param info datatype info of the channel + * + * @return channel type **/ - virtual void SetChannelType(const std::string& channel_name, const std::string& type) = 0; + virtual void SetChannelDataTypeInformation(const SChannel& channel, const eCAL::eh5::DataTypeInformation& info) = 0; /** * @brief Gets minimum timestamp for specified channel @@ -166,7 +150,7 @@ namespace eCAL * * @return minimum timestamp value **/ - virtual long long GetMinTimestamp(const std::string& channel_name) const = 0; + virtual long long GetMinTimestamp(const SChannel& channel) const = 0; /** * @brief Gets maximum timestamp for specified channel @@ -175,7 +159,7 @@ namespace eCAL * * @return maximum timestamp value **/ - virtual long long GetMaxTimestamp(const std::string& channel_name) const = 0; + virtual long long GetMaxTimestamp(const SChannel& channel) const = 0; /** * @brief Gets the header info for all data entries for the given channel @@ -186,7 +170,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - virtual bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const = 0; + virtual bool GetEntriesInfo(const SChannel& channel, EntryInfoSet& entries) const = 0; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) @@ -199,7 +183,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - virtual bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const = 0; + virtual bool GetEntriesInfoRange(const SChannel& channel, long long begin, long long end, EntryInfoSet& entries) const = 0; /** * @brief Gets data size of a specific entry @@ -241,7 +225,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - virtual bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) = 0; + virtual bool AddEntryToFile(const SWriteEntry& entry) = 0; typedef std::function CallbackFunction; /** diff --git a/contrib/ecalhdf5/src/escape.cpp b/contrib/ecalhdf5/src/escape.cpp index dfc37c75ec..cce41dfb8f 100644 --- a/contrib/ecalhdf5/src/escape.cpp +++ b/contrib/ecalhdf5/src/escape.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -576,6 +576,18 @@ namespace eCAL return GetEscapedString(non_escaped_topicname, is_reserved_topicname_); } + SChannel GetEscapedTopicname(const SChannel& input) + { + return SChannel(GetEscapedTopicname(input.name), input.id); + } + + SWriteEntry GetEscapedEntry(const SWriteEntry& input) + { + SWriteEntry escaped_entry{ input }; + escaped_entry.channel = GetEscapedTopicname(input.channel); + return escaped_entry; + } + std::string GetEscapedFilename(const std::string& non_escaped_filename) { return GetEscapedString(non_escaped_filename, is_reserved_filename_); diff --git a/contrib/ecalhdf5/src/escape.h b/contrib/ecalhdf5/src/escape.h index 4e979c7b92..cd26027964 100644 --- a/contrib/ecalhdf5/src/escape.h +++ b/contrib/ecalhdf5/src/escape.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,12 +20,15 @@ #pragma once #include +#include namespace eCAL { namespace eh5 { std::string GetEscapedTopicname(const std::string& input); + SChannel GetEscapedTopicname(const SChannel& input); + SWriteEntry GetEscapedEntry(const SWriteEntry& input); std::string GetEscapedFilename(const std::string& input); std::string GetUnescapedString(const std::string& input); } diff --git a/contrib/ecalhdf5/src/hdf5_helper.cpp b/contrib/ecalhdf5/src/hdf5_helper.cpp new file mode 100644 index 0000000000..2e09a92a56 --- /dev/null +++ b/contrib/ecalhdf5/src/hdf5_helper.cpp @@ -0,0 +1,293 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2024 - 2025 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +#include "hdf5_helper.h" + +bool CreateStringEntryInRoot(hid_t root, const std::string& url, const std::string& dataset_content) +{ + // create scalar dataset + hid_t scalar_dataspace = H5Screate(H5S_SCALAR); + // create new string data type + hid_t string_data_type = H5Tcopy(H5T_C_S1); + + // if attribute's value length exists, allocate space for it + if (dataset_content.length() > 0) + H5Tset_size(string_data_type, dataset_content.length()); + // Create creation property for data_space + auto ds_property = H5Pcreate(H5P_DATASET_CREATE); + H5Pset_obj_track_times(ds_property, false); + //H5Pset_create_intermediate_group(ds_property, 1); + + // create attribute + hid_t data_set = H5Dcreate(root, url.c_str(), string_data_type, scalar_dataspace, H5P_DEFAULT, ds_property, H5P_DEFAULT); + if (data_set < 0) return false; + + auto write_status = H5Dwrite(data_set, string_data_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, dataset_content.c_str()); + if (write_status < 0) return false; + + // close all created stuff + H5Dclose(data_set); + H5Pclose(ds_property); + H5Tclose(string_data_type); + H5Sclose(scalar_dataspace); + + return true; +} + + +bool ReadStringEntryAsString(hid_t root, const std::string& url, std::string& data) +{ + // empty attribute value + data.clear(); + if (root < 0) return false; + + auto dataset_id = H5Dopen(root, url.c_str(), H5P_DEFAULT); + if (dataset_id < 0) return false; + + auto size = H5Dget_storage_size(dataset_id); + data.resize(size); + + herr_t read_status = -1; + if (size >= 0) + { + hid_t string_data_type = H5Tcopy(H5T_C_S1); + H5Tset_size(string_data_type, size); + read_status = H5Dread(dataset_id, string_data_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, static_cast(const_cast(data.data()))); + } + + H5Dclose(dataset_id); + return (read_status >= 0); +} + +// status = H5Dread(dset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); +bool CreateBinaryEntryInRoot(hid_t root, const std::string& url, const std::string& dataset_content) +{ + + hsize_t hs_size = static_cast(dataset_content.size()); + // Create DataSpace with rank 1 and size dimension + auto data_space = H5Screate_simple(1, &hs_size, nullptr); + // Create creation property for data_space + auto ds_property = H5Pcreate(H5P_DATASET_CREATE); + H5Pset_obj_track_times(ds_property, false); + //H5Pset_create_intermediate_group(ds_property, 1); + // Create dataset in data_space + auto data_set = H5Dcreate(root, url.c_str(), H5T_NATIVE_UCHAR, data_space, H5P_DEFAULT, ds_property, H5P_DEFAULT); + + // Write buffer to dataset + herr_t write_status = H5Dwrite(data_set, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, dataset_content.c_str()); + + // Close dataset, data space, and data set property + H5Dclose(data_set); + H5Pclose(ds_property); + H5Sclose(data_space); + + return (write_status >= 0); +} + +bool ReadBinaryEntryAsString(hid_t root, const std::string& url, std::string& data) +{ + data.clear(); + + auto dataset_id = H5Dopen(root, url.c_str(), H5P_DEFAULT); + if (dataset_id < 0) return false; + + auto size = H5Dget_storage_size(dataset_id); + data.resize(size); + + herr_t read_status = -1; + if (size >= 0) + { + read_status = H5Dread(dataset_id, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, static_cast(const_cast(data.data()))); + } + + H5Dclose(dataset_id); + return (read_status >= 0); +} + + +bool CreateInformationEntryInRoot(hid_t root, const std::string& url, const eCAL::eh5::EntryInfoVect& entries) +{ + const size_t dataSetsSize = entries.size(); + hsize_t dims[2] = { dataSetsSize, 5 }; + // Create DataSpace with rank 2 and size dimension + auto dataSpace = H5Screate_simple(2, dims, nullptr); + // Create creation property for data_space + auto dsProperty = H5Pcreate(H5P_DATASET_CREATE); + H5Pset_obj_track_times(dsProperty, false); + auto dataSet = H5Dcreate(root, url.c_str(), H5T_NATIVE_LLONG, dataSpace, H5P_DEFAULT, dsProperty, H5P_DEFAULT); + if (dataSet < 0) return false; + + // Write buffer to dataset + herr_t writeStatus = H5Dwrite(dataSet, H5T_NATIVE_LLONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, entries.data()); + if (writeStatus < 0) return false; + + // Close dataset, data space, and data set property + H5Dclose(dataSet); + H5Pclose(dsProperty); + H5Sclose(dataSpace); + + return true; +} + +bool GetEntryInfoVector(hid_t root, const std::string& url, eCAL::eh5::EntryInfoSet& entries) +{ + entries.clear(); + + auto dataset_id = H5Dopen(root, url.c_str(), H5P_DEFAULT); + + if (dataset_id < 0) return false; + + const size_t sizeof_ll = sizeof(long long); + hsize_t data_size = H5Dget_storage_size(dataset_id) / sizeof_ll; + + if (data_size <= 0) return false; + + std::vector data(data_size); + herr_t status = H5Dread(dataset_id, H5T_NATIVE_LLONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, &data[0]); + H5Dclose(dataset_id); + + for (unsigned int index = 0; index < data_size; index += 5) + { + // rec timestamp, channel id, send clock, send time stamp, send ID + entries.emplace(eCAL::eh5::SEntryInfo(data[index], data[index + 1], data[index + 2], data[index + 3], data[index + 4])); + } + + return (status >= 0); +} + +bool SetAttribute(hid_t id, const std::string& name, const std::string& value) +{ + if (id < 0) return false; + + if (H5Aexists(id, name.c_str()) > 0) + H5Adelete(id, name.c_str()); + // create scalar dataset + hid_t scalarDataset = H5Screate(H5S_SCALAR); + + // create new string data type + hid_t stringDataType = H5Tcopy(H5T_C_S1); + + // if attribute's value length exists, allocate space for it + if (value.length() > 0) + H5Tset_size(stringDataType, value.length()); + + // create attribute + hid_t attribute = H5Acreate(id, name.c_str(), stringDataType, scalarDataset, H5P_DEFAULT, H5P_DEFAULT); + + if (attribute < 0) return false; + + // write attribute value to attribute + herr_t writeStatus = H5Awrite(attribute, stringDataType, value.c_str()); + if (writeStatus < 0) return false; + + // close attribute + H5Aclose(attribute); + // close scalar dataset + H5Sclose(scalarDataset); + // close string data type + H5Tclose(stringDataType); + + return true; +} + +bool GetAttribute(hid_t id, const std::string& name, std::string& value) +{ + bool ret_val = false; + // empty attribute value + value.clear(); + if (id < 0) return false; + + // check if attribute exists + if (H5Aexists(id, name.c_str()) != 0) + { + // open attribute by name, getting the attribute index + hid_t attr_id = H5Aopen_name(id, name.c_str()); + // fail - attribute can not be opened + if (attr_id <= 0) return false; + + // get attribute type + hid_t attr_type = H5Aget_type(attr_id); + // get type class based on attribute type + H5T_class_t type_class = H5Tget_class(attr_type); + // get attribute content dataSize + const size_t attr_size = H5Tget_size(attr_type); + + // if attribute class is string + if (type_class == H5T_STRING) + { + hid_t attr_type_mem = H5Tget_native_type(attr_type, H5T_DIR_ASCEND); + // create buffer to store the value of the attribute + std::vector content_buffer(attr_size); + // get attribute value + ret_val = (H5Aread(attr_id, attr_type_mem, &content_buffer[0]) >= 0); + + // convert value to std string + value = std::string(&content_buffer[0], attr_size); + } + else + { + // fail - attribute is not string type + ret_val = false; + } + // close attribute + H5Aclose(attr_id); + } + else + { + // fail - attribute name does not exist + ret_val = false; + } + // return read status + return ret_val; +} + +bool HasGroup(hid_t root, const std::string& path) +{ + hid_t exists = H5Lexists(root, path.c_str(), H5P_DEFAULT); + return (exists > 0); +} + +hid_t OpenOrCreateGroup(hid_t root, const std::string& name) +{ + hid_t group; + if (HasGroup(root, name)) + { + group = H5Gopen(root, name.c_str(), H5P_DEFAULT); + } + else + { + group = H5Gcreate(root, name.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + } + + return group; +} + +std::vector ListSubgroups(hid_t id) +{ + std::vector group_vector; + auto iterate_lambda = [](hid_t /*group*/, const char* name, const H5L_info_t* /*info*/, void* op_data)->herr_t + { + auto vec = static_cast*>(op_data); + vec->push_back(name); + return 0; + }; + + H5Literate(id, H5_INDEX_NAME, H5_ITER_INC, nullptr, iterate_lambda, (void*)&group_vector); + return group_vector; +} \ No newline at end of file diff --git a/contrib/ecalhdf5/src/hdf5_helper.h b/contrib/ecalhdf5/src/hdf5_helper.h new file mode 100644 index 0000000000..d8e4a56ebc --- /dev/null +++ b/contrib/ecalhdf5/src/hdf5_helper.h @@ -0,0 +1,86 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2024 - 2025 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +#pragma once + +#include +#include +#include + +#include + +#include + +bool CreateStringEntryInRoot(hid_t root, const std::string& url, const std::string& dataset_content); +bool ReadStringEntryAsString(hid_t root, const std::string& url, std::string& data); + +bool CreateBinaryEntryInRoot(hid_t root, const std::string& url, const std::string& dataset_content); +bool ReadBinaryEntryAsString(hid_t root, const std::string& url, std::string& data); + +bool CreateInformationEntryInRoot(hid_t root, const std::string& url, const eCAL::eh5::EntryInfoVect& entries); +bool GetEntryInfoVector(hid_t root, const std::string& url, eCAL::eh5::EntryInfoSet& entries); + +/** +* @brief Set attribute to object(file, entry...) +* +* @param id ID of the attributes parent +* @param name Name of the attribute +* @param value Value of the attribute +* +* @return true if succeeds, false if it fails +**/ +bool SetAttribute(hid_t id, const std::string& name, const std::string& value); +/** +* @brief Gets the value of a string attribute +* +* @param [in] obj_id ID of the attribute's parent +* @param [in] name Name of the attribute +* @param [out] value Value of the attribute +* +* @return true if succeeds, false if it fails +**/ +bool GetAttribute(hid_t id, const std::string& name, std::string& value); + +bool HasGroup(hid_t root, const std::string& path); + +hid_t OpenOrCreateGroup(hid_t root, const std::string& name); + +std::vector ListSubgroups(hid_t id); + + +inline std::string printHex(eCAL::experimental::measurement::base::Channel::id_t id) +{ + std::stringstream ss; + ss << std::hex << std::setw(16) << std::setfill('0') << std::uppercase << id; + return ss.str(); +} + +inline eCAL::experimental::measurement::base::Channel::id_t parseHexID(std::string string_id) +{ + return std::stoull(string_id, nullptr, 16); +} + +namespace v6 +{ + inline std::string GetUrl(const std::string& channel_name_, const std::string& channel_id, const std::string& attribute) + { + return "/" + channel_name_ + "/" + channel_id + "/" + attribute; + //return "/" + channel_name_ + "/" + attribute; + } +} \ No newline at end of file diff --git a/contrib/ecalproto/CMakeLists.txt b/contrib/ecalproto/CMakeLists.txt deleted file mode 100644 index 04f1a1b9a6..0000000000 --- a/contrib/ecalproto/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -# ========================= eCAL LICENSE ================================= -# -# Copyright (C) 2016 - 2019 Continental Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ========================= eCAL LICENSE ================================= - -find_package(Protobuf REQUIRED) - -project(proto) - -set(ecal_protobuf_src - src/ecal_proto_decoder.cpp - src/ecal_proto_dyn.cpp - src/ecal_proto_maximum_array_dimensions.cpp - src/ecal_proto_message_filter.cpp - src/ecal_proto_visitor.cpp -) - -set(ecal_protobuf_header - include/ecal/protobuf/ecal_proto_decoder.h - include/ecal/protobuf/ecal_proto_dyn.h - include/ecal/protobuf/ecal_proto_hlp.h - include/ecal/protobuf/ecal_proto_maximum_array_dimensions.h - include/ecal/protobuf/ecal_proto_message_filter.h - include/ecal/protobuf/ecal_proto_visitor.h -) - -ecal_add_library(${PROJECT_NAME} ${ecal_protobuf_src} ${ecal_protobuf_header}) -add_library(eCAL::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_include_directories(${PROJECT_NAME} PUBLIC - $ - $ -) - -target_link_libraries(${PROJECT_NAME} PUBLIC protobuf::libprotobuf) - -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) - -ecal_install_library(${PROJECT_NAME}) - -install( - FILES ${ecal_protobuf_header} - DESTINATION "${INSTALL_INCLUDE_DIR}/ecal/protobuf" - COMPONENT sdk -) - -set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER contrib) diff --git a/contrib/ecalproto/src/ecal_proto_dyn.cpp b/contrib/ecalproto/src/ecal_proto_dyn.cpp deleted file mode 100644 index 0e53dec6fe..0000000000 --- a/contrib/ecalproto/src/ecal_proto_dyn.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ========================= eCAL LICENSE ================================= -*/ - -/** - * dynamic protobuf message decoder -**/ - -#include - -#include -#include -#include -#include - -namespace eCAL -{ -namespace protobuf -{ - - class ParserErrorCollector : public google::protobuf::io::ErrorCollector - { - public: - ParserErrorCollector() {} - ~ParserErrorCollector() {} - - std::string Get() { return(m_ss.str()); } - - // Indicates that there was an error in the input at the given line and - // column numbers. The numbers are zero-based, so you may want to add - // 1 to each before printing them. - void AddError(int line_, int column_, const std::string& msg_) - { - Add(line_, column_, "ERROR: " + msg_); - } - - // Indicates that there was a warning in the input at the given line and - // column numbers. The numbers are zero-based, so you may want to add - // 1 to each before printing them. - void AddWarning(int line_, int column_, const std::string& msg_) - { - Add(line_, column_, "WARNING: " + msg_); - } - - private: - void Add(int line_, int column_, const std::string& msg_) - { - m_ss << line_ << ":" << column_ << " " << msg_ << std::endl; - } - - std::stringstream m_ss; - }; - - class DescriptorErrorCollector : public google::protobuf::DescriptorPool::ErrorCollector - { - public: - DescriptorErrorCollector() {} - ~DescriptorErrorCollector() {} - - std::string Get() { return(m_ss.str()); } - - void AddError( - const std::string& filename, // File name in which the error occurred. - const std::string& element_name, // Full name of the erroneous element. - const google::protobuf::Message* descriptor, // Descriptor of the erroneous element. - ErrorLocation location, // One of the location constants, above. - const std::string& message // Human-readable error message. - ) - { - Add(filename, element_name, descriptor, location, "ERROR: " + message); - } - - void AddWarning( - const std::string& filename, // File name in which the error occurred. - const std::string& element_name, // Full name of the erroneous element. - const google::protobuf::Message* descriptor, // Descriptor of the erroneous element. - ErrorLocation location, // One of the location constants, above. - const std::string& message // Human-readable error message. - ) - { - Add(filename, element_name, descriptor, location, "WARNING: " + message); - } - - private: - void Add( - const std::string& filename, - const std::string& element_name, - const google::protobuf::Message* /*descriptor*/, - ErrorLocation location, - const std::string& message - ) - { - m_ss << filename << " " << element_name << " " << location << " " << message << std::endl; - } - - std::stringstream m_ss; - }; - - google::protobuf::Message* CProtoDynDecoder::GetProtoMessageFromFile(const std::string& proto_filename_, const std::string& msg_type_, std::string& error_s_) - { - google::protobuf::FileDescriptorProto proto; - if (!GetFileDescriptorFromFile(proto_filename_, &proto, error_s_)) return(nullptr); - google::protobuf::FileDescriptorSet pset; - google::protobuf::FileDescriptorProto* pdesc = pset.add_file(); - pdesc->CopyFrom(proto); - return(GetProtoMessageFromDescriptorSet(pset, msg_type_, error_s_)); - } - - google::protobuf::Message* CProtoDynDecoder::GetProtoMessageFromString(const std::string& proto_string_, const std::string& msg_type_, std::string& error_s_) - { - google::protobuf::FileDescriptorProto proto; - if (!GetFileDescriptorFromString(proto_string_, &proto, error_s_)) return(nullptr); - google::protobuf::FileDescriptorSet pset; - google::protobuf::FileDescriptorProto* pdesc = pset.add_file(); - pdesc->CopyFrom(proto); - return(GetProtoMessageFromDescriptorSet(pset, msg_type_, error_s_)); - } - - google::protobuf::Message* CProtoDynDecoder::GetProtoMessageFromDescriptor(const google::protobuf::FileDescriptorProto& proto_desc_, const std::string& msg_type_, std::string& error_s_) - { - google::protobuf::FileDescriptorSet pset; - google::protobuf::FileDescriptorProto* pdesc = pset.add_file(); - pdesc->CopyFrom(proto_desc_); - return(GetProtoMessageFromDescriptorSet(pset, msg_type_, error_s_)); - } - - google::protobuf::Message* CProtoDynDecoder::GetProtoMessageFromDescriptor(const std::string& msg_desc_, const std::string& msg_type_, std::string& error_s_) - { - // create file descriptor set - google::protobuf::FileDescriptorSet pset; - if (!pset.ParseFromString(msg_desc_)) - { - error_s_ = "Cannot get file descriptor of message: " + msg_type_; - return(nullptr); - } - - // create message object - google::protobuf::Message* proto_msg = GetProtoMessageFromDescriptorSet(pset, msg_type_, error_s_); - if (!proto_msg) - { - return(nullptr); - } - - return(proto_msg); - } - - google::protobuf::Message* CProtoDynDecoder::GetProtoMessageFromDescriptorSet(const google::protobuf::FileDescriptorSet& proto_desc_set_, const std::string& msg_type_, std::string& error_s_) - { - // check if msg_type_ is available in descriptor pool - const google::protobuf::Descriptor* desc = m_descriptor_pool.FindMessageTypeByName(msg_type_); - if (desc != nullptr) - { - const google::protobuf::Message* prototype_msg = m_message_factory.GetPrototype(desc); - if (prototype_msg != nullptr) - { - // ownership passed to caller here ! - google::protobuf::Message* proto_msg = prototype_msg->New(); - if (proto_msg == nullptr) - { - error_s_ = "Failed in prototype_msg->New(); to create mutable message"; - return(nullptr); - } - return(proto_msg); - } - } - - // suppose you want to parse a message type with a specific type name. - DescriptorErrorCollector error_collector; - const google::protobuf::FileDescriptor* file_desc = nullptr; - for (auto it = 0; it < proto_desc_set_.file_size(); ++it) - { - file_desc = m_descriptor_pool.BuildFileCollectingErrors(proto_desc_set_.file(it), &error_collector); - if (file_desc == nullptr) - { - error_s_ = error_collector.Get(); - return(nullptr); - } - if ((file_desc->message_type_count() > 0) && - (file_desc->message_type(0)->name() == msg_type_)) - { - break; - } - } - if (file_desc == nullptr) - { - error_s_ = "Cannot get file descriptor of message: " + msg_type_; - return(nullptr); - } - const google::protobuf::Descriptor* message_desc = file_desc->FindMessageTypeByName(msg_type_); - if (message_desc == nullptr) - { - error_s_ = "Cannot get message descriptor of message: " + msg_type_; - return(nullptr); - } - - const google::protobuf::Message* prototype_msg = m_message_factory.GetPrototype(message_desc); - if (prototype_msg == nullptr) - { - error_s_ = "Cannot create prototype message from message descriptor"; - return(nullptr); - } - - // ownership passed to caller here ! - google::protobuf::Message* proto_msg = prototype_msg->New(); - if (proto_msg == nullptr) - { - error_s_ = "Failed in prototype_msg->New(); to create mutable message"; - return(nullptr); - } - return(proto_msg); - } - - google::protobuf::DescriptorPool* CProtoDynDecoder::GetDescriptorPool() - { - return &m_descriptor_pool; - } - - bool CProtoDynDecoder::GetFileDescriptorFromFile(const std::string& proto_filename_, google::protobuf::FileDescriptorProto* file_desc_proto_, std::string& error_s_) - { - using namespace google::protobuf; - using namespace google::protobuf::io; - using namespace google::protobuf::compiler; - - std::ifstream fs(proto_filename_); - if (!fs.is_open()) - { - std::cout << "Cannot open .proto file: " << proto_filename_; - return(false); - } - std::stringstream ss; - ss << fs.rdbuf(); - - std::string proto_str = ss.str(); - - return(GetFileDescriptorFromString(proto_str, file_desc_proto_, error_s_)); - } - - bool CProtoDynDecoder::GetFileDescriptorFromString(const std::string& proto_string_, google::protobuf::FileDescriptorProto* file_desc_proto_, std::string& error_s_) - { - using namespace google::protobuf; - using namespace google::protobuf::io; - using namespace google::protobuf::compiler; - - std::stringstream ss; - ss << proto_string_; - IstreamInputStream proto_string_input_stream(&ss); - - Tokenizer tokenizer(&proto_string_input_stream, nullptr); - Parser parser; - ParserErrorCollector error_collector; - parser.RecordErrorsTo(&error_collector); - if (!parser.Parse(&tokenizer, file_desc_proto_)) - { - error_s_ = error_collector.Get(); - return(false); - } - - // here we walk around a bug in protocol buffers that - // |Parser::Parse| does not set name (.proto filename) in - // file_desc_proto. - if (!file_desc_proto_->has_name()) - { - file_desc_proto_->set_name("foo.proto"); - } - - return(true); - } -} -} diff --git a/contrib/ecaltime/ecaltime_pb/CMakeLists.txt b/contrib/ecaltime/ecaltime_pb/CMakeLists.txt index 4c4dc0ab16..3c4e9982b6 100644 --- a/contrib/ecaltime/ecaltime_pb/CMakeLists.txt +++ b/contrib/ecaltime/ecaltime_pb/CMakeLists.txt @@ -57,15 +57,9 @@ target_compile_options(${PROJECT_NAME} set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(${PROJECT_NAME} protobuf::libprotobuf) +target_link_libraries(${PROJECT_NAME} PUBLIC protobuf::libprotobuf) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) ecal_install_library(${PROJECT_NAME}) -if(BUILD_PY_BINDING) - protobuf_generate_python_ext(python_sources ${PYTHON_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src ${ProtoFiles}) - target_sources(${PROJECT_NAME} PRIVATE ${python_sources}) - set_source_files_properties(${python_sources} PROPERTIES HEADER_FILE_ONLY TRUE) -endif() - set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER contrib/ecaltime/ecaltime_pb) diff --git a/contrib/ecaltime/linuxptp/CMakeLists.txt b/contrib/ecaltime/linuxptp/CMakeLists.txt index 01b1f69898..e07be4a0cc 100644 --- a/contrib/ecaltime/linuxptp/CMakeLists.txt +++ b/contrib/ecaltime/linuxptp/CMakeLists.txt @@ -18,7 +18,7 @@ project(ecaltime-linuxptp) -find_package(simpleini REQUIRED) +find_package(yaml-cpp REQUIRED) set(ecal_time_linuxptp_src src/ecal_time_linuxptp.cpp @@ -38,7 +38,7 @@ endif() ecal_add_time_plugin(${PROJECT_NAME} SHARED ${ecal_time_linuxptp_src} ${ecal_time_linuxptp_header}) -target_link_libraries(${PROJECT_NAME} eCAL::core simpleini::simpleini) +target_link_libraries(${PROJECT_NAME} PRIVATE eCAL::core yaml-cpp::yaml-cpp) target_include_directories(${PROJECT_NAME} PRIVATE @@ -49,7 +49,7 @@ ecal_install_time_plugin(${PROJECT_NAME}) set(ECALTIME_CONFIG_FILES ${ECALTIME_CONFIG_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/src/config/ecaltime.ini + ${CMAKE_CURRENT_SOURCE_DIR}/src/config/ecaltime.yaml PARENT_SCOPE) set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/contrib/ecaltime/linuxptp/src/config/config.h b/contrib/ecaltime/linuxptp/src/config/config.h index 096686bbc0..804fa627a5 100644 --- a/contrib/ecaltime/linuxptp/src/config/config.h +++ b/contrib/ecaltime/linuxptp/src/config/config.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,12 @@ #pragma once -#include +#include #include #include #include -#include +#include namespace LinuxPtpConfig { @@ -32,20 +32,28 @@ namespace LinuxPtpConfig { * @brief reads the file ~/.ecal/ecaltime.ini to get the device * @return the device value from the linuxptp section */ - std::string getDevice() { - CSimpleIniA ini; - - std::string path_to_ini = eCAL::Util::GeteCALConfigPath(); - path_to_ini += "ecaltime.ini"; - - int err = ini.LoadFile(path_to_ini.c_str()); - if (err != SI_OK){ - std::cerr << "Error reading ecaltime config file" << std::endl; + std::string getDevice() { + std::string path_to_ini = eCAL::Util::GeteCALDataDir(); + path_to_ini += "/ecaltime.yaml"; + + YAML::Node yaml; + try + { + yaml = YAML::LoadFile(path_to_ini); + } + catch(const std::exception& e) + { + std::cerr << "Error reading ecaltime config file: " << e.what() << "\n"; + } + + if (yaml["linuxptp"]) + { + if (yaml["linuxptp"]["device"]) + { + return yaml["linuxptp"]["device"].as(); + } } - const char * pVal = ini.GetValue("linuxptp", "device", "/dev/ptp0"); - - std::string device(pVal); - return device; + return std::string("/dev/ptp0"); } } diff --git a/contrib/ecaltime/linuxptp/src/config/ecaltime.ini b/contrib/ecaltime/linuxptp/src/config/ecaltime.ini deleted file mode 100644 index 31c0dc00a3..0000000000 --- a/contrib/ecaltime/linuxptp/src/config/ecaltime.ini +++ /dev/null @@ -1,15 +0,0 @@ -; --------------------------------------------- -; ecaltime-linuxptp Settings -; --------------------------------------------- -; -; device = /dev/ptp0 The device can be any ptp clock. -; Alternatively, you can use: -; - CLOCK_MONOTONIC (a steady clock with undefined epoche) -; - CLOCK_REALTIME (the current system time) -; - CLOCK_TAI (Like CLOCK_REALTIME but in International Atomic Time) -; -; --------------------------------------------- -[linuxptp] -device = /dev/ptp0 - - diff --git a/contrib/ecaltime/linuxptp/src/config/ecaltime.yaml b/contrib/ecaltime/linuxptp/src/config/ecaltime.yaml new file mode 100644 index 0000000000..35e841ec16 --- /dev/null +++ b/contrib/ecaltime/linuxptp/src/config/ecaltime.yaml @@ -0,0 +1,13 @@ +# --------------------------------------------- +# ecaltime-linuxptp Settings +# --------------------------------------------- +# +# device = /dev/ptp0 The device can be any ptp clock. +# Alternatively, you can use: +# - CLOCK_MONOTONIC (a steady clock with undefined epoche) +# - CLOCK_REALTIME (the current system time) +# - CLOCK_TAI (Like CLOCK_REALTIME but in International Atomic Time) +# +# --------------------------------------------- +linuxptp: + device: "/dev/ptp0" diff --git a/contrib/ecaltime/linuxptp/src/ecaltime.cpp b/contrib/ecaltime/linuxptp/src/ecaltime.cpp index cc249b87a1..88f46817e5 100644 --- a/contrib/ecaltime/linuxptp/src/ecaltime.cpp +++ b/contrib/ecaltime/linuxptp/src/ecaltime.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "ecal_time_linuxptp.h" #include "config/config.h" diff --git a/contrib/ecaltime/localtime/CMakeLists.txt b/contrib/ecaltime/localtime/CMakeLists.txt index 13bcf105b3..bd7d145f77 100644 --- a/contrib/ecaltime/localtime/CMakeLists.txt +++ b/contrib/ecaltime/localtime/CMakeLists.txt @@ -43,7 +43,7 @@ target_include_directories(${PROJECT_NAME} $ $) -target_link_libraries(${PROJECT_NAME} +target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads $<$,$>,$>>:rt> ) diff --git a/contrib/ecaltime/simtime/CMakeLists.txt b/contrib/ecaltime/simtime/CMakeLists.txt index 6b4951c710..ba3f469a53 100644 --- a/contrib/ecaltime/simtime/CMakeLists.txt +++ b/contrib/ecaltime/simtime/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -45,7 +45,7 @@ ecal_add_time_plugin(${PROJECT_NAME} SHARED ${ecal_time_simtime_src} ${ecal_time target_compile_definitions(${PROJECT_NAME} PRIVATE ECAL_TIME_PLUGIN_API_EXPORT) -target_link_libraries(${PROJECT_NAME} PRIVATE eCAL::core) +target_link_libraries(${PROJECT_NAME} PRIVATE eCAL::protobuf_core) target_link_libraries(${PROJECT_NAME} PRIVATE eCAL::ecaltime_pb) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14) diff --git a/contrib/ecaltime/simtime/src/ecal_time_simtime.cpp b/contrib/ecaltime/simtime/src/ecal_time_simtime.cpp index 98e748cbd9..2c13f12330 100644 --- a/contrib/ecaltime/simtime/src/ecal_time_simtime.cpp +++ b/contrib/ecaltime/simtime/src/ecal_time_simtime.cpp @@ -38,22 +38,20 @@ eCAL::CSimTime::CSimTime() : bool eCAL::CSimTime::initialize() { std::unique_lock lk(initialize_mutex); - if (!is_initialized) { - //eCAL::Initialize(0, NULL, "ecal_sim_time_listener", eCAL::Init::Subscriber); + if (!is_initialized) + { + //eCAL::Initialize("ecal_sim_time_listener", eCAL::Init::Subscriber); // this has to be done by the parent process // needs to be fixed with an improved reference counting // in eCAL::Initialize .. - if (sim_time_subscriber.Create("__sim_time__")) { - sim_time_subscriber.AddReceiveCallback(std::bind(&eCAL::CSimTime::onSimTimeMessage, this, std::placeholders::_2)); - is_initialized = true; - } - else { - is_initialized = false; - } - return is_initialized; + sim_time_subscriber = std::make_unique>("__sim_time__"); + sim_time_subscriber->SetReceiveCallback(std::bind(&eCAL::CSimTime::onSimTimeMessage, this, std::placeholders::_2)); + is_initialized = true; + return true; } - else { + else + { return false; } } diff --git a/contrib/ecaltime/simtime/src/ecal_time_simtime.h b/contrib/ecaltime/simtime/src/ecal_time_simtime.h index 07f653ac9e..dff95a3418 100644 --- a/contrib/ecaltime/simtime/src/ecal_time_simtime.h +++ b/contrib/ecaltime/simtime/src/ecal_time_simtime.h @@ -113,7 +113,7 @@ namespace eCAL bool first_message_received; /**< Whether we received at least one Message (used for the status message)*/ eCAL::pb::SimTime::eState play_state; /**< Current state (used for the status message)*/ - eCAL::protobuf::CSubscriber sim_time_subscriber; /**< Subscriber for getting simulation timestamps */ + std::unique_ptr> sim_time_subscriber; /**< Subscriber for getting simulation timestamps */ std::mutex time_mutex; /**< Mutex for computing the current simulation time */ long long last_measurement_time; /**< Last received simulation time */ diff --git a/contrib/measurement/base/include/ecal/measurement/base/reader.h b/contrib/measurement/base/include/ecal/measurement/base/reader.h index 521ece05f1..fcc9999075 100644 --- a/contrib/measurement/base/include/ecal/measurement/base/reader.h +++ b/contrib/measurement/base/include/ecal/measurement/base/reader.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -114,76 +114,81 @@ namespace eCAL * * @return channel names **/ - virtual std::set GetChannelNames() const = 0; + /*virtual std::set GetChannelNames() const = 0;*/ /** - * @brief Check if channel exists in measurement + * @brief Get the available channel names of the current opened file / measurement * - * @param channel_name name of the channel + * @return Channels (channel name & id) + **/ + virtual std::set GetChannels() const = 0; + + /** + * @brief Get the available channel names of the current opened file / measurement * - * @return true if exists, false otherwise + * @return Channels (channel name & id) **/ - virtual bool HasChannel(const std::string& channel_name) const = 0; + /*virtual std::set GetChannels(const std::string& channel_name) const = 0;*/ /** - * @brief Get the channel description for the given channel + * @brief Check if channel exists in measurement * - * @param channel_name channel name + * @param channel The channel (channel name & id) * - * @return channel description + * @return true if exists, false otherwise **/ - virtual std::string GetChannelDescription(const std::string& channel_name) const = 0; + virtual bool HasChannel(const eCAL::experimental::measurement::base::Channel& channel) const = 0; /** - * @brief Gets the channel type of the given channel + * @brief Get data type information of the given channel * - * @param channel_name channel name + * @param channel (channel name & id) * * @return channel type **/ - virtual std::string GetChannelType(const std::string& channel_name) const = 0; + virtual DataTypeInformation GetChannelDataTypeInformation(const eCAL::experimental::measurement::base::Channel& channel) const = 0; /** * @brief Gets minimum timestamp for specified channel * - * @param channel_name channel name + * @param channel (channel name & id) * * @return minimum timestamp value **/ - virtual long long GetMinTimestamp(const std::string& channel_name) const = 0; + virtual long long GetMinTimestamp(const eCAL::experimental::measurement::base::Channel& channel) const = 0; /** * @brief Gets maximum timestamp for specified channel * - * @param channel_name channel name + * @param channel (channel name & id) * * @return maximum timestamp value **/ - virtual long long GetMaxTimestamp(const std::string& channel_name) const = 0; + virtual long long GetMaxTimestamp(const eCAL::experimental::measurement::base::Channel & channel) const = 0; /** * @brief Gets the header info for all data entries for the given channel * Header = timestamp + entry id * - * @param [in] channel_name channel name + * @param [in] channel (channel name & id) * @param [out] entries header info for all data entries * * @return true if succeeds, false if it fails **/ - virtual bool GetEntriesInfo(const std::string& channel_name, EntryInfoSet& entries) const = 0; + virtual bool GetEntriesInfo(const eCAL::experimental::measurement::base::Channel & channel, EntryInfoSet& entries) const = 0; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) * Header = timestamp + entry id * - * @param [in] channel_name channel name + * @param [in] channel (channel name & id) * @param [in] begin time range begin timestamp * @param [in] end time range end timestamp * @param [out] entries header info for data entries in given range * * @return true if succeeds, false if it fails **/ - virtual bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, EntryInfoSet& entries) const = 0; + virtual bool GetEntriesInfoRange(const eCAL::experimental::measurement::base::Channel& channel, long long begin, long long end, EntryInfoSet& entries) const = 0; /** * @brief Gets data size of a specific entry diff --git a/contrib/measurement/base/include/ecal/measurement/base/types.h b/contrib/measurement/base/include/ecal/measurement/base/types.h index 34fa97b6cd..821f30bce1 100644 --- a/contrib/measurement/base/include/ecal/measurement/base/types.h +++ b/contrib/measurement/base/include/ecal/measurement/base/types.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,10 @@ #pragma once +#include #include +#include +#include #include namespace eCAL @@ -36,16 +39,94 @@ namespace eCAL { namespace base { + /** + * @brief Optional compile time information associated with a given topic + * (necessary for reflection / runtime type checking) + **/ + struct DataTypeInformation + { + std::string name = ""; //!< name of the datatype + std::string encoding = ""; //!< encoding of the datatype (e.g. protobuf, flatbuffers, capnproto) + std::string descriptor = ""; //!< descriptor information of the datatype (necessary for reflection) + + //!< @cond + bool operator==(const DataTypeInformation& other) const + { + return std::tie(name, encoding, descriptor) == std::tie(other.name, other.encoding, other.descriptor); + } + + bool operator!=(const DataTypeInformation& other) const + { + return !(*this == other); + } + + bool operator<(const DataTypeInformation& other) const + { + return std::tie(name, encoding, descriptor) < std::tie(other.name, other.encoding, other.descriptor); + } + //!< @endcond + }; + + struct Channel + { + using id_t = std::uint64_t; + + std::string name = ""; + id_t id = 0; + + Channel() = default; + Channel(const std::string name_, id_t id_) : name(name_), id(id_) {}; + + //!< @cond + bool operator==(const Channel& other) const + { + return std::tie(id, name) == std::tie(other.id, other.name); + } + + bool operator!=(const Channel& other) const + { + return !(*this == other); + } + + bool operator<(const Channel& other) const + { + return std::tie(id, name) < std::tie(other.id, other.name); + } + //!< @endcond + }; + + inline Channel CreateChannel(const std::string& name) + { + return Channel{ name, 0 }; + } + + struct WriteEntry + { + // channel + Channel channel; + + // data + const void* data = nullptr; + unsigned long long size = 0; + + // metadata + long long snd_timestamp = 0; + long long rcv_timestamp = 0; + long long sender_id = 0; // Unique ID which may be set by sender + long long clock = 0; + }; + + /** * @brief Info struct for a single measurement entry **/ struct EntryInfo { long long RcvTimestamp; //!< Receive time stamp - long long ID; //!< Channel ID + long long ID; //!< Data ID - to extract corresponding data long long SndClock; //!< Send clock long long SndTimestamp; //!< Send time stamp - long long SndID; //!< Send ID + long long SndID; //!< Send ID (!= channel ID!!!!) //!< @cond EntryInfo() : RcvTimestamp(0), ID(0), SndClock(0), SndTimestamp(0), SndID(0) {} @@ -80,16 +161,21 @@ namespace eCAL **/ using EntryInfoVect = std::vector; - /** - * @brief eCAL Measurement Access types - **/ - enum AccessType - { - RDONLY, //!< ReadOnly - the measurement can only be read - CREATE //!< Create - a new measurement will be created - }; - } } } +} + +namespace std { + template <> + struct hash { + std::size_t operator()(const eCAL::experimental::measurement::base::Channel& data) const { + // Combine the hash of the string and the integer + std::size_t h1 = std::hash{}(data.name); + std::size_t h2 = std::hash{}(data.id); + + // Combine the two hashes (this is a common technique) + return h1 ^ (h2 << 1); // XOR and shift + } + }; } \ No newline at end of file diff --git a/contrib/measurement/base/include/ecal/measurement/base/writer.h b/contrib/measurement/base/include/ecal/measurement/base/writer.h index 72fff0a07b..c092fcd3f5 100644 --- a/contrib/measurement/base/include/ecal/measurement/base/writer.h +++ b/contrib/measurement/base/include/ecal/measurement/base/writer.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,20 +139,14 @@ namespace eCAL virtual void SetOneFilePerChannelEnabled(bool enabled) = 0; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel - **/ - virtual void SetChannelDescription(const std::string& channel_name, const std::string& description) = 0; - - /** - * @brief Set type of the given channel + * @brief Set data type information of the given channel * * @param channel_name channel name - * @param type type of the channel + * @param info datatype info of the channel + * + * @return channel type **/ - virtual void SetChannelType(const std::string& channel_name, const std::string& type) = 0; + virtual void SetChannelDataTypeInformation(const eCAL::experimental::measurement::base::Channel& channel_name, const DataTypeInformation& info) = 0; /** * @brief Set measurement file base name (desired name for the actual hdf5 files that will be created) @@ -174,8 +168,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - virtual bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) = 0; - + virtual bool AddEntryToFile(const base::WriteEntry& entry) = 0; }; } } diff --git a/contrib/measurement/base/include/ecal/measurement/imeasurement.h b/contrib/measurement/base/include/ecal/measurement/imeasurement.h index 95d89f8da1..11bc011a72 100644 --- a/contrib/measurement/base/include/ecal/measurement/imeasurement.h +++ b/contrib/measurement/base/include/ecal/measurement/imeasurement.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,11 +35,11 @@ namespace eCAL class IBinaryChannel { public: - IBinaryChannel(std::shared_ptr meas_, std::string name_) - : channel_name(name_) + IBinaryChannel(std::shared_ptr meas_, experimental::measurement::base::Channel channel_) + : channel(channel_) , meas(meas_) { - meas->GetEntriesInfo(channel_name, entry_infos); + meas->GetEntriesInfo(channel, entry_infos); } virtual BinaryFrame operator[](const experimental::measurement::base::EntryInfo& entry) @@ -53,7 +53,7 @@ namespace eCAL std::string name() { - return channel_name; + return channel.name; } class iterator /*: public std::iterator>*/ @@ -100,7 +100,7 @@ namespace eCAL mutable std::string m_msg; }; - bool operator==(const IBinaryChannel& rhs) const { return channel_name == rhs.channel_name && meas == rhs.meas; /*return it == rhs.it; */ }; + bool operator==(const IBinaryChannel& rhs) const { return channel == rhs.channel && meas == rhs.meas; /*return it == rhs.it; */ }; bool operator!=(const IBinaryChannel& rhs) const { return !(operator==(rhs)); /*return it == rhs.it; */ }; iterator begin() @@ -114,7 +114,7 @@ namespace eCAL } private: - const std::string channel_name; + const experimental::measurement::base::Channel channel; std::shared_ptr meas; mutable experimental::measurement::base::EntryInfoSet entry_infos; mutable std::string data; @@ -125,8 +125,8 @@ namespace eCAL class IChannel { public: - IChannel(std::shared_ptr meas_, std::string name_) - : binary_channel(meas_, name_) + IChannel(std::shared_ptr meas_, const experimental::measurement::base::Channel& channel_) + : binary_channel(meas_, channel_) { } @@ -219,10 +219,11 @@ namespace eCAL public: IMeasurement(const std::string& path); - ChannelSet ChannelNames() const; + ChannelSet Channels() const; + ChannelSet Channels(const std::string& channel_name) const; template - IChannel Get(const std::string& channel) const; + IChannel Get(const experimental::measurement::base::Channel& channel) const; private: std::shared_ptr meas; @@ -233,9 +234,23 @@ namespace eCAL { } - inline ChannelSet IMeasurement::ChannelNames() const + inline ChannelSet IMeasurement::Channels() const { - return meas->GetChannelNames(); + return meas->GetChannels(); + } + + // This is probably not very performant. We should check! + inline ChannelSet IMeasurement::Channels(const std::string& channel_name) const + { + ChannelSet channels_filtered_by_name; + auto all_channels = meas->GetChannels(); + for (const auto& channel : all_channels) { + if (channel.name == channel_name) + { + channels_filtered_by_name.insert(channel); + } + } + return channels_filtered_by_name; } // This will return a nullptr if channel name and @@ -243,14 +258,14 @@ namespace eCAL // a) channel does not exist in the IMeasurement // b) the registered type does not match with the descriptor in the chanenel template - inline IChannel IMeasurement::Get(const std::string& channel) const + inline IChannel IMeasurement::Get(const experimental::measurement::base::Channel& channel) const { // Assert that the channel is in the IMeasurement - auto channels = ChannelNames(); + auto channels = Channels(); if (channels.find(channel) == channels.end()) { // Throw an exception, if channel is not available? - throw std::out_of_range("The channel " + channel + " does not exist in this measurement"); + throw std::out_of_range("The channel {" + channel.name + ", " + std::to_string(channel.id) + "} does not exist in this measurement"); } // Assert that the channel type is compatible with the requested type diff --git a/contrib/measurement/base/include/ecal/measurement/measurement.h b/contrib/measurement/base/include/ecal/measurement/measurement.h index 720445d5d4..19ece11e8c 100644 --- a/contrib/measurement/base/include/ecal/measurement/measurement.h +++ b/contrib/measurement/base/include/ecal/measurement/measurement.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ namespace eCAL { namespace measurement { - using ChannelSet = std::set; + using ChannelSet = std::set; struct SenderID { diff --git a/contrib/measurement/base/include/ecal/measurement/omeasurement.h b/contrib/measurement/base/include/ecal/measurement/omeasurement.h index a75d2780fa..46fe1d0fc2 100644 --- a/contrib/measurement/base/include/ecal/measurement/omeasurement.h +++ b/contrib/measurement/base/include/ecal/measurement/omeasurement.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,36 +34,46 @@ namespace eCAL class OBinaryChannel { public: - OBinaryChannel(std::shared_ptr meas_, const std::string& name_) - : channel_name(name_) + OBinaryChannel(std::shared_ptr meas_, const std::string& name_, const eCAL::experimental::measurement::base::DataTypeInformation& datatype_info) + : channel(name_, 0) , meas(meas_) - , SenderID(0) + , id(0) , clock(0) { + meas->SetChannelDataTypeInformation(channel, datatype_info); } OBinaryChannel& operator<<(const BinaryFrame& entry_) { - meas->AddEntryToFile((void*)entry_.message.data(), entry_.message.size(), entry_.send_timestamp, entry_.receive_timestamp, channel_name, SenderID, clock); + eCAL::experimental::measurement::base::WriteEntry entry; + entry.channel = channel; + entry.data = entry_.message.data(); + entry.size = entry_.message.size(); + entry.snd_timestamp = entry_.send_timestamp; + entry.rcv_timestamp = entry_.receive_timestamp; + entry.sender_id = id; + entry.clock = clock; + + meas->AddEntryToFile(entry); ++clock; return *this; } OBinaryChannel& operator<<(const SenderID& id_) { - SenderID = id_.ID; + id = id_.ID; return *this; } - bool operator==(const OBinaryChannel& rhs) const { return channel_name == rhs.channel_name && meas == rhs.meas; /*return it == rhs.it; */ }; + bool operator==(const OBinaryChannel& rhs) const { return channel == rhs.channel && meas == rhs.meas; /*return it == rhs.it; */ }; bool operator!=(const OBinaryChannel& rhs) const { return !(operator==(rhs)); /*return it == rhs.it; */ }; private: - const std::string channel_name; + const experimental::measurement::base::Channel channel; std::shared_ptr meas; - long long SenderID; + long long id; long long clock; }; @@ -72,8 +82,8 @@ namespace eCAL class OChannel { public: - OChannel(std::shared_ptr meas_, std::string name_) - : binary_channel(meas_, name_) + OChannel(std::shared_ptr meas_, std::string name_, const eCAL::experimental::measurement::base::DataTypeInformation& datatype_info) + : binary_channel(meas_, name_, datatype_info) { } @@ -132,10 +142,13 @@ namespace eCAL inline OChannel OMeasurement::Create(const std::string& channel) const { static T msg; - meas->SetChannelType(channel, eCAL::message::GetTypeName(msg)); - meas->SetChannelDescription(channel, eCAL::message::GetDescription(msg)); - // Construct a channel based - return OChannel{meas, channel}; + const eCAL::experimental::measurement::base::DataTypeInformation datatype_info{ + eCAL::message::GetTypeName(msg), + eCAL::message::GetEncoding(msg), + eCAL::message::GetDescription(msg) + }; + // Construct a channel based + return OChannel{meas, channel, datatype_info}; } diff --git a/contrib/measurement/hdf5/include/ecal/measurement/hdf5/reader.h b/contrib/measurement/hdf5/include/ecal/measurement/hdf5/reader.h index be27f56c10..f5eeb21111 100644 --- a/contrib/measurement/hdf5/include/ecal/measurement/hdf5/reader.h +++ b/contrib/measurement/hdf5/include/ecal/measurement/hdf5/reader.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,20 +27,16 @@ #include #include - namespace eCAL { - namespace eh5 - { - class HDF5Meas; - } - namespace experimental { namespace measurement { namespace hdf5 { + struct ReaderImpl; + /** * @brief Hdf5 based Reader Implementation **/ @@ -124,34 +120,39 @@ namespace eCAL * * @return channel names **/ - std::set GetChannelNames() const override; + //std::set GetChannelNames() const override; /** - * @brief Check if channel exists in measurement + * @brief Get the available channel names of the current opened file / measurement * - * @param channel_name name of the channel + * @return Channels (channel name & id) + **/ + std::set GetChannels() const override; + + /** + * @brief Get the available channel names of the current opened file / measurement * - * @return true if exists, false otherwise + * @return Channels (channel name & id) **/ - bool HasChannel(const std::string& channel_name) const override; + //std::set GetChannels(const std::string& channel_name) const override; /** - * @brief Get the channel description for the given channel + * @brief Check if channel exists in measurement * - * @param channel_name channel name + * @param channel_name name of the channel * - * @return channel description + * @return true if exists, false otherwise **/ - std::string GetChannelDescription(const std::string& channel_name) const override; + bool HasChannel(const eCAL::experimental::measurement::base::Channel& channel) const override; /** - * @brief Gets the channel type of the given channel + * @brief Get data type information of the given channel * * @param channel_name channel name * * @return channel type **/ - std::string GetChannelType(const std::string& channel_name) const override; + base::DataTypeInformation GetChannelDataTypeInformation(const eCAL::experimental::measurement::base::Channel& channel) const override; /** * @brief Gets minimum timestamp for specified channel @@ -160,7 +161,7 @@ namespace eCAL * * @return minimum timestamp value **/ - long long GetMinTimestamp(const std::string& channel_name) const override; + long long GetMinTimestamp(const eCAL::experimental::measurement::base::Channel& channel) const override; /** * @brief Gets maximum timestamp for specified channel @@ -169,7 +170,7 @@ namespace eCAL * * @return maximum timestamp value **/ - long long GetMaxTimestamp(const std::string& channel_name) const override; + long long GetMaxTimestamp(const eCAL::experimental::measurement::base::Channel& channel) const override; /** * @brief Gets the header info for all data entries for the given channel @@ -180,7 +181,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfo(const std::string& channel_name, measurement::base::EntryInfoSet& entries) const override; + bool GetEntriesInfo(const eCAL::experimental::measurement::base::Channel& channel, measurement::base::EntryInfoSet& entries) const override; /** * @brief Gets the header info for data entries for the given channel included in given time range (begin->end) @@ -193,7 +194,7 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, measurement::base::EntryInfoSet& entries) const override; + bool GetEntriesInfoRange(const eCAL::experimental::measurement::base::Channel& channel, long long begin, long long end, measurement::base::EntryInfoSet& entries) const override; /** * @brief Gets data size of a specific entry @@ -216,7 +217,7 @@ namespace eCAL bool GetEntryData(long long entry_id, void* data) const override; private: - std::unique_ptr measurement; + std::unique_ptr impl; }; diff --git a/contrib/measurement/hdf5/include/ecal/measurement/hdf5/writer.h b/contrib/measurement/hdf5/include/ecal/measurement/hdf5/writer.h index c7de047568..3d11703a47 100644 --- a/contrib/measurement/hdf5/include/ecal/measurement/hdf5/writer.h +++ b/contrib/measurement/hdf5/include/ecal/measurement/hdf5/writer.h @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,17 +33,14 @@ namespace eCAL { - namespace eh5 - { - class HDF5Meas; - } - namespace experimental { namespace measurement { namespace hdf5 { + struct WriterImpl; + /** * @brief Hdf5 based Writer implementation **/ @@ -149,20 +146,14 @@ namespace eCAL void SetOneFilePerChannelEnabled(bool enabled) override; /** - * @brief Set description of the given channel - * - * @param channel_name channel name - * @param description description of the channel - **/ - void SetChannelDescription(const std::string& channel_name, const std::string& description) override; - - /** - * @brief Set type of the given channel + * @brief Set data type information of the given channel * * @param channel_name channel name - * @param type type of the channel + * @param info datatype info of the channel + * + * @return channel type **/ - void SetChannelType(const std::string& channel_name, const std::string& type) override; + void SetChannelDataTypeInformation(const eCAL::experimental::measurement::base::Channel& channel, const base::DataTypeInformation& info) override; /** * @brief Set measurement file base name (desired name for the actual hdf5 files that will be created) @@ -184,10 +175,10 @@ namespace eCAL * * @return true if succeeds, false if it fails **/ - bool AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) override; + bool AddEntryToFile(const base::WriteEntry& entry) override; private: - std::unique_ptr measurement; + std::unique_ptr impl; }; } // namespace hdf5 } // namespace measurement diff --git a/contrib/measurement/hdf5/src/reader.cpp b/contrib/measurement/hdf5/src/reader.cpp index 320e7308f9..064d7df48d 100644 --- a/contrib/measurement/hdf5/src/reader.cpp +++ b/contrib/measurement/hdf5/src/reader.cpp @@ -1,15 +1,38 @@ #include #include + using namespace eCAL::experimental::measurement::hdf5; using namespace eCAL::experimental::measurement; +namespace eCAL +{ + namespace experimental + { + namespace measurement + { + namespace hdf5 + { + struct ReaderImpl + { + eCAL::eh5::HDF5Meas measurement; + + ReaderImpl() = default; + ReaderImpl(const std::string& path) + : measurement(path, eCAL::eh5::eAccessType::RDONLY) + {} + }; + } + } + } +} + Reader::Reader() - : measurement(std::make_unique()) + : impl(std::make_unique()) {} Reader::Reader(const std::string& path) - : measurement(std::make_unique(path, eh5::eAccessType::RDONLY)) + : impl(std::make_unique(path)) {} Reader::~Reader() = default; @@ -20,70 +43,77 @@ Reader& Reader::operator=(Reader&&) noexcept = default; bool Reader::Open(const std::string& path) { - return measurement->Open(path, eh5::eAccessType::RDONLY); + return impl->measurement.Open(path, eCAL::eh5::eAccessType::RDONLY); } bool Reader::Close() { - return measurement->Close(); + return impl->measurement.Close(); } bool Reader::IsOk() const { - return measurement->IsOk(); + return impl->measurement.IsOk(); } std::string Reader::GetFileVersion() const { - return measurement->GetFileVersion(); + return impl->measurement.GetFileVersion(); } +/* std::set Reader::GetChannelNames() const { - return measurement->GetChannelNames(); -} + return impl->measurement.GetChannelNames(); +}*/ -bool Reader::HasChannel(const std::string& channel_name) const +std::set eCAL::experimental::measurement::hdf5::Reader::GetChannels() const { - return measurement->HasChannel(channel_name); + return impl->measurement.GetChannels(); } -std::string Reader::GetChannelDescription(const std::string& channel_name) const +/* +std::set eCAL::experimental::measurement::hdf5::Reader::GetChannels(const std::string& channel_name) const +{ + return impl->measurement.GetChannels(channel_name); +}*/ + +bool Reader::HasChannel(const eCAL::experimental::measurement::base::Channel& channel) const { - return measurement->GetChannelDescription(channel_name); + return impl->measurement.HasChannel(channel); } -std::string Reader::GetChannelType(const std::string& channel_name) const +base::DataTypeInformation Reader::GetChannelDataTypeInformation(const base::Channel& channel) const { - return measurement->GetChannelType(channel_name); + return impl->measurement.GetChannelDataTypeInformation(channel); } -long long Reader::GetMinTimestamp(const std::string& channel_name) const +long long Reader::GetMinTimestamp(const base::Channel& channel) const { - return measurement->GetMinTimestamp(channel_name); + return impl->measurement.GetMinTimestamp(channel); } -long long Reader::GetMaxTimestamp(const std::string& channel_name) const +long long Reader::GetMaxTimestamp(const base::Channel& channel) const { - return measurement->GetMaxTimestamp(channel_name); + return impl->measurement.GetMaxTimestamp(channel); } -bool Reader::GetEntriesInfo(const std::string& channel_name, base::EntryInfoSet& entries) const +bool Reader::GetEntriesInfo(const base::Channel& channel, base::EntryInfoSet& entries) const { - return measurement->GetEntriesInfo(channel_name, entries); + return impl->measurement.GetEntriesInfo(channel, entries); } -bool Reader::GetEntriesInfoRange(const std::string& channel_name, long long begin, long long end, base::EntryInfoSet& entries) const +bool Reader::GetEntriesInfoRange(const base::Channel& channel, long long begin, long long end, base::EntryInfoSet& entries) const { - return measurement->GetEntriesInfoRange(channel_name, begin, end, entries); + return impl->measurement.GetEntriesInfoRange(channel, begin, end, entries); } bool Reader::GetEntryDataSize(long long entry_id, size_t& size) const { - return measurement->GetEntryDataSize(entry_id, size); + return impl->measurement.GetEntryDataSize(entry_id, size); } bool Reader::GetEntryData(long long entry_id, void* data) const { - return measurement->GetEntryData(entry_id, data); + return impl->measurement.GetEntryData(entry_id, data); } \ No newline at end of file diff --git a/contrib/measurement/hdf5/src/writer.cpp b/contrib/measurement/hdf5/src/writer.cpp index e8cd2a1c38..783a73838a 100644 --- a/contrib/measurement/hdf5/src/writer.cpp +++ b/contrib/measurement/hdf5/src/writer.cpp @@ -4,12 +4,34 @@ using namespace eCAL::experimental::measurement::hdf5; using namespace eCAL::experimental::measurement; +namespace eCAL +{ + namespace experimental + { + namespace measurement + { + namespace hdf5 + { + struct WriterImpl + { + eCAL::eh5::HDF5Meas measurement; + + WriterImpl() = default; + WriterImpl(const std::string& path) + : measurement(path, eCAL::eh5::eAccessType::CREATE) + {} + }; + } + } + } +} + Writer::Writer() - : measurement(std::make_unique()) + : impl(std::make_unique()) {} Writer::Writer(const std::string& path) - : measurement(std::make_unique(path, eh5::eAccessType::CREATE)) + : impl(std::make_unique(path)) {} Writer::~Writer() = default; @@ -20,55 +42,50 @@ Writer& Writer::operator=(Writer&&) noexcept = default; bool Writer::Open(const std::string& path) { - return measurement->Open(path, eh5::eAccessType::CREATE); + return impl->measurement.Open(path, eCAL::eh5::eAccessType::CREATE); } bool Writer::Close() { - return measurement->Close(); + return impl->measurement.Close(); } bool Writer::IsOk() const { - return measurement->IsOk(); + return impl->measurement.IsOk(); } size_t Writer::GetMaxSizePerFile() const { - return measurement->GetMaxSizePerFile(); + return impl->measurement.GetMaxSizePerFile(); } void Writer::SetMaxSizePerFile(size_t size) { - return measurement->SetMaxSizePerFile(size); + return impl->measurement.SetMaxSizePerFile(size); } bool Writer::IsOneFilePerChannelEnabled() const { - return measurement->IsOneFilePerChannelEnabled(); + return impl->measurement.IsOneFilePerChannelEnabled(); } void Writer::SetOneFilePerChannelEnabled(bool enabled) { - return measurement->SetOneFilePerChannelEnabled(enabled); -} - -void Writer::SetChannelDescription(const std::string& channel_name, const std::string& description) -{ - return measurement->SetChannelDescription(channel_name, description); + return impl->measurement.SetOneFilePerChannelEnabled(enabled); } -void Writer::SetChannelType(const std::string& channel_name, const std::string& type) +void Writer::SetChannelDataTypeInformation(const base::Channel& channel_name, const base::DataTypeInformation& info) { - return measurement->SetChannelType(channel_name, type); + impl->measurement.SetChannelDataTypeInformation(channel_name, info); } void Writer::SetFileBaseName(const std::string& base_name) { - return measurement->SetFileBaseName(base_name); + return impl->measurement.SetFileBaseName(base_name); } -bool Writer::AddEntryToFile(const void* data, const unsigned long long& size, const long long& snd_timestamp, const long long& rcv_timestamp, const std::string& channel_name, long long id, long long clock) +bool Writer::AddEntryToFile(const base::WriteEntry& entry) { - return measurement->AddEntryToFile(data, size, snd_timestamp, rcv_timestamp, channel_name, id, clock); + return impl->measurement.AddEntryToFile(entry); } diff --git a/contrib/message/CMakeLists.txt b/contrib/message/CMakeLists.txt deleted file mode 100644 index b7942a460d..0000000000 --- a/contrib/message/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# ========================= eCAL LICENSE ================================= -# -# Copyright (C) 2016 - 2019 Continental Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ========================= eCAL LICENSE ================================= - -project(message) - -set(ecal_message_header - include/ecal/msg/proto/message.h - include/ecal/msg/string/message.h - include/ecal/msg/message.h -) - -add_library(${PROJECT_NAME} INTERFACE) -add_library(eCAL::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) - -target_include_directories(${PROJECT_NAME} INTERFACE - $ - $ -) - -ecal_install_library(${PROJECT_NAME}) - -install(DIRECTORY - "include/" DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT sdk -) - - diff --git a/contrib/message/include/ecal/msg/message.h b/contrib/message/include/ecal/msg/message.h deleted file mode 100644 index 96da5fbc39..0000000000 --- a/contrib/message/include/ecal/msg/message.h +++ /dev/null @@ -1,44 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -/* -A type needs to implement the following functions in order that a measurement object -can be constructed for that type (read / write) -*/ -namespace eCAL -{ - namespace message - { - //// unfortunately, we need an actual object for this :/ - //template - //std::string GetTypeName(const T& message); - - //// unfortunately, we need an actual object for this :/ - //template - //std::string GetDescription(const T& message); - - //template - //bool Serialize(const T& message, std::string& buffer); - - //template - //bool Deserialize(const std::string& buffer, T& message); - } -} \ No newline at end of file diff --git a/contrib/message/include/ecal/msg/proto/message.h b/contrib/message/include/ecal/msg/proto/message.h deleted file mode 100644 index e3520e863d..0000000000 --- a/contrib/message/include/ecal/msg/proto/message.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4100 4127 4146 4505 4800 4189 4592) // disable proto warnings -#endif -#include -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#include -#include - -namespace eCAL -{ - namespace message - { - // unfortunately, we need an actual object for this :/ - inline std::string GetTypeName(const google::protobuf::Message& message) - { - return("proto:" + message.GetTypeName()); - } - - // unfortunately, we need an actual object for this :/ - inline std::string GetDescription(const google::protobuf::Message& message) - { - return eCAL::protobuf::GetProtoMessageDescription(message); - } - - inline bool Serialize(const google::protobuf::Message& message, std::string& buffer) - { - return message.SerializeToString(&buffer); - } - - inline bool Deserialize(const std::string& buffer, google::protobuf::Message& message) - { - return message.ParseFromString(buffer); - } - } -} \ No newline at end of file diff --git a/contrib/message/include/ecal/msg/string/message.h b/contrib/message/include/ecal/msg/string/message.h deleted file mode 100644 index 3aecef9406..0000000000 --- a/contrib/message/include/ecal/msg/string/message.h +++ /dev/null @@ -1,54 +0,0 @@ -/* ========================= eCAL LICENSE ================================= - * - * Copyright (C) 2016 - 2019 Continental Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * ========================= eCAL LICENSE ================================= -*/ - -#pragma once - -#include - -#include - -namespace eCAL -{ - namespace message - { - // unfortunately, we need an actual object for this :/ - inline std::string GetTypeName(const std::string& /*message*/) - { - return("base:std::string"); - } - - // unfortunately, we need an actual object for this :/ - inline std::string GetDescription(const std::string& /*message*/) - { - return(""); - } - - inline bool Serialize(const std::string& message, std::string& buffer) - { - buffer = message; - return true; - } - - inline bool Deserialize(const std::string& buffer, std::string& message) - { - message = buffer; - return true; - } - } -} \ No newline at end of file diff --git a/contrib/mma/CMakeLists.txt b/contrib/mma/CMakeLists.txt index 5d1c072098..c915a69aa0 100644 --- a/contrib/mma/CMakeLists.txt +++ b/contrib/mma/CMakeLists.txt @@ -1,6 +1,6 @@ # ========================= eCAL LICENSE ================================= # -# Copyright (C) 2016 - 2019 Continental Corporation +# Copyright (C) 2016 - 2025 Continental Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -80,10 +80,10 @@ target_include_directories(${PROJECT_NAME} create_targets_protobuf() -target_link_libraries(${PROJECT_NAME} - protobuf::libprotobuf +target_link_libraries(${PROJECT_NAME} PRIVATE Threads::Threads - eCAL::core eCAL::app_pb + eCAL::protobuf_core + eCAL::app_pb $<$:Pdh> $<$:wbemuuid.lib>) diff --git a/contrib/mma/include/linux/mma_linux.h b/contrib/mma/include/linux/mma_linux.h index 724006664c..3b02bffd4b 100644 --- a/contrib/mma/include/linux/mma_linux.h +++ b/contrib/mma/include/linux/mma_linux.h @@ -17,6 +17,12 @@ * ========================= eCAL LICENSE ================================= */ +#include +#include +#include +#include +#include +#include #ifdef __unix__ #include diff --git a/contrib/mma/include/linux/pipe_refresher.h b/contrib/mma/include/linux/pipe_refresher.h index ea739b5fa1..44def8e41a 100644 --- a/contrib/mma/include/linux/pipe_refresher.h +++ b/contrib/mma/include/linux/pipe_refresher.h @@ -19,11 +19,11 @@ #pragma once +#include #ifdef __unix__ #include #include -#include #include #include diff --git a/contrib/mma/include/logger.h b/contrib/mma/include/logger.h index 67c687c9aa..9c5d34ed08 100644 --- a/contrib/mma/include/logger.h +++ b/contrib/mma/include/logger.h @@ -19,9 +19,7 @@ #pragma once -#include #include -#include #include class Logger diff --git a/contrib/mma/include/windows/mma_windows.h b/contrib/mma/include/windows/mma_windows.h index 84e7ca8818..c168198095 100644 --- a/contrib/mma/include/windows/mma_windows.h +++ b/contrib/mma/include/windows/mma_windows.h @@ -78,6 +78,8 @@ class MMAWindows : public MMAImpl QueryManager query_manager_; std::shared_ptr processor_; std::shared_ptr memory_; + std::shared_ptr disk_; + std::shared_ptr network_; std::shared_ptr processes_; std::list> total_network_cards_; diff --git a/contrib/mma/include/windows/network.h b/contrib/mma/include/windows/network.h index 18833956fb..4a3a528eb5 100644 --- a/contrib/mma/include/windows/network.h +++ b/contrib/mma/include/windows/network.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include #include diff --git a/contrib/mma/src/linux/mma_linux.cpp b/contrib/mma/src/linux/mma_linux.cpp index 52fc3308f5..74c3ac0c19 100644 --- a/contrib/mma/src/linux/mma_linux.cpp +++ b/contrib/mma/src/linux/mma_linux.cpp @@ -17,6 +17,17 @@ * ========================= eCAL LICENSE ================================= */ +#include "ecal/app/pb/mma/mma.pb.h" +#include "linux/pipe_refresher.h" +#include "linux/ressource.h" +#include +#include +#include +#include +#include +#include +#include +#include #ifdef __unix__ #include diff --git a/contrib/mma/src/linux/pipe_refresher.cpp b/contrib/mma/src/linux/pipe_refresher.cpp index 2dc49817ef..b90f91f1c3 100644 --- a/contrib/mma/src/linux/pipe_refresher.cpp +++ b/contrib/mma/src/linux/pipe_refresher.cpp @@ -17,10 +17,14 @@ * ========================= eCAL LICENSE ================================= */ +#include +#include +#include +#include +#include #ifdef __unix__ #include -#include #include "../include/linux/pipe_refresher.h" diff --git a/contrib/mma/src/logger.cpp b/contrib/mma/src/logger.cpp index 5f44f222cd..f761f0394c 100644 --- a/contrib/mma/src/logger.cpp +++ b/contrib/mma/src/logger.cpp @@ -19,7 +19,11 @@ #include "../include/logger.h" +#include +#include +#include #include +#include Logger* Logger::this_ = nullptr; std::ofstream Logger::log_file_; diff --git a/contrib/mma/src/mma.cpp b/contrib/mma/src/mma.cpp index 7d084939ab..3f5059ed2b 100644 --- a/contrib/mma/src/mma.cpp +++ b/contrib/mma/src/mma.cpp @@ -18,6 +18,7 @@ */ #include "../include/mma.h" +#include "ecal/app/pb/mma/mma.pb.h" #ifdef _WIN32 #include "../include/windows/mma_windows.h" diff --git a/contrib/mma/src/mma_application.cpp b/contrib/mma/src/mma_application.cpp index d8c5e1394e..118972ab79 100644 --- a/contrib/mma/src/mma_application.cpp +++ b/contrib/mma/src/mma_application.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2025 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,24 +19,23 @@ #include #include -#include +#include #include #include #include #include "ecal/ecal.h" -#include "ecal/ecal_process.h" +#include "ecal/process.h" #include "ecal/msg/protobuf/publisher.h" #include "../include/logger.h" #include "../include/mma.h" #include "../include/mma_defs.h" #include "../include/zombie_instance_killer.h" -#include "../include/interruptable_timer.h" #ifdef _MSC_VER #pragma warning(push) -#pragma warning(disable: 4100 4127 4146 4505 4800 4189 4592) // disable proto warnings +#pragma warning(disable : 4100 4127 4146 4505 4800 4189 4592) // disable proto warnings #endif #include #ifdef _MSC_VER @@ -49,17 +48,12 @@ #include #include #else -#include #include -#include -#include #include #include #include #include #include -#include -#include #include #include @@ -141,7 +135,7 @@ int main(int argc, char** argv) std::cout << app_version_header << std::endl << ecal_version_header << std::endl << std::endl; // initialize eCAL API - if (eCAL::Initialize(0, nullptr, MMA_APPLICATION_NAME, eCAL::Init::Publisher | eCAL::Init::ProcessReg) < 0) + if (eCAL::Initialize(MMA_APPLICATION_NAME, eCAL::Init::Publisher)) { std::cout << "eCAL initialization failed !"; return 1; @@ -153,7 +147,7 @@ int main(int argc, char** argv) Logger::getLogger()->ResumeLogging(); } - eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Running"); + eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Running"); // create mma agent std::cout << std::endl << "Initializing machine monitoring agent ..." << std::endl; diff --git a/contrib/mma/src/query_manager.cpp b/contrib/mma/src/query_manager.cpp index 42a38d9de2..7588864926 100644 --- a/contrib/mma/src/query_manager.cpp +++ b/contrib/mma/src/query_manager.cpp @@ -18,6 +18,7 @@ */ #include "../include/query_manager.h" +#include QueryManager::QueryManager() { diff --git a/contrib/mma/src/windows/mma_windows.cpp b/contrib/mma/src/windows/mma_windows.cpp index a659c765df..70def504bc 100644 --- a/contrib/mma/src/windows/mma_windows.cpp +++ b/contrib/mma/src/windows/mma_windows.cpp @@ -87,22 +87,28 @@ bool MMAWindows::init() pdhStatus = PdhOpenQuery(nullptr, 0, &h_query_); CheckPDH("PdhOpenQuery", pdhStatus); + // PROCESSOR processor_ = std::make_shared(); processor_->RefreshData(h_query_, pdhStatus); + // MEMORY memory_ = std::make_shared(); - Disk disk_resource; - total_disks_ = disk_resource.GetResourceInfo(h_query_, pdhStatus, query_manager_); + // DISK + disk_ = std::make_shared(); + total_disks_ = disk_->GetResourceInfo(h_query_, pdhStatus, query_manager_); - Network network_resource; - total_network_cards_ = network_resource.GetResourceInfo(h_query_, pdhStatus, query_manager_); + // NETWORK + network_ = std::make_shared(); + total_network_cards_ = network_->GetResourceInfo(h_query_, pdhStatus, query_manager_); pdhStatus = PdhCollectQueryData(h_query_); CheckPDH("PdhCollectQueryData", pdhStatus); + // PROCESSES processes_ = std::make_shared(); + nr_of_cpu_cores = processor_->GetNumbersOfCpuCores(); // the nr. of cores is static show we need to call once this function lpBuffer = new char[4026]; _In_ UINT uSize = 0; @@ -147,12 +153,10 @@ bool MMAWindows::Get(eCAL::pb::mma::State& state) state.clear_disks(); state.clear_networks(); - Disk disk; - auto disks = disk.GetResourceInfo(h_query_, pdhStatus, query_manager_); + auto disks = disk_->GetResourceInfo(h_query_, pdhStatus, query_manager_); RefreshResource(total_disks_, disks); - Network network; - auto networks = network.GetResourceInfo(h_query_, pdhStatus, query_manager_); + auto networks = network_->GetResourceInfo(h_query_, pdhStatus, query_manager_); RefreshResource(total_network_cards_, networks); memory_->RefreshData(); diff --git a/contrib/mma/src/zombie_instance_killer.cpp b/contrib/mma/src/zombie_instance_killer.cpp index c35a95f899..ab628a83e8 100644 --- a/contrib/mma/src/zombie_instance_killer.cpp +++ b/contrib/mma/src/zombie_instance_killer.cpp @@ -17,6 +17,8 @@ * ========================= eCAL LICENSE ================================= */ +#include +#include #include #include #include @@ -29,13 +31,12 @@ #endif #ifdef __linux__ -#include #include #include #include #endif -#include "ecal/ecal_process.h" +#include "ecal/process.h" #include "../include/zombie_instance_killer.h" bool ZombieInstanceKiller::KillZombieInstance(const std::list& process_names) diff --git a/cpack/innosetup.cmake b/cpack/innosetup.cmake index 221879e9d4..ef80d6b2f9 100644 --- a/cpack/innosetup.cmake +++ b/cpack/innosetup.cmake @@ -25,8 +25,8 @@ if (ISSC_PATH STREQUAL "ISSC_PATH-NOTFOUND") message(FATAL_ERROR "Unable to find Innosetup (ISCC.exe)") else() message(STATUS "Found Innosetup at ${ISSC_PATH}") - exec_program("${ISSC_PATH}" - ARGS - "${CPACK_TOPLEVEL_DIRECTORY}/innosetup/ecal_setup.iss" + execute_process( + COMMAND "${ISSC_PATH}" "${CPACK_TOPLEVEL_DIRECTORY}/innosetup/ecal_setup.iss" + WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}/innosetup" ) endif() diff --git a/cpack/innosetup/ecal_setup.iss.in b/cpack/innosetup/ecal_setup.iss.in index bfe4d41ac6..a3ffbc343f 100644 --- a/cpack/innosetup/ecal_setup.iss.in +++ b/cpack/innosetup/ecal_setup.iss.in @@ -1,6 +1,6 @@ ; ========================= eCAL LICENSE ================================= ; -; Copyright (C) 2016 - 2019 Continental Corporation +; Copyright (C) 2016 - 2024 Continental Corporation ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. @@ -49,7 +49,7 @@ ChangesAssociations=yes ; PrivilegesRequired=admin ; Only available in Version 6 and above: PrivilegesRequiredOverridesAllowed=dialog -ArchitecturesInstallIn64BitMode=x64 +ArchitecturesInstallIn64BitMode=x64compatible ChangesEnvironment=true VersionInfoVersion={#AppVersion} LicenseFile={#LicenseFile} @@ -75,13 +75,18 @@ Source: "{#ComponentStagingDir}\runtime\*"; DestDir: "{app}"; Fla Source: "{#ComponentStagingDir}\Unspecified\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: runtime Source: "{#ComponentStagingDir}\libraries\bin\*"; DestDir: "{app}\bin\"; Flags: ignoreversion recursesubdirs; Components: runtime -Source: "{#ComponentStagingDir}\configuration\cfg\ecal.ini"; DestDir: "{commonappdata}\eCAL\"; Tasks: not replaceconf; Flags: ignoreversion confirmoverwrite; Components: runtime -Source: "{#ComponentStagingDir}\configuration\cfg\ecal.ini"; DestDir: "{commonappdata}\eCAL\"; Tasks: replaceconf; Flags: ignoreversion; Components: runtime -Source: "{#ComponentStagingDir}\configuration\cfg\ecaltime.ini"; DestDir: "{commonappdata}\eCAL\"; Flags: ignoreversion; Components: runtime +; we need to change the location of these configuration file (as hotfix we use skipifsourcedoesntexist flag) +Source: "{#ComponentStagingDir}\configuration\cfg\ecal.yaml"; DestDir: "{commonappdata}\eCAL\"; Tasks: not replaceconf; Flags: ignoreversion skipifsourcedoesntexist confirmoverwrite; Components: runtime +Source: "{#ComponentStagingDir}\configuration\cfg\ecal.yaml"; DestDir: "{commonappdata}\eCAL\"; Tasks: replaceconf; Flags: ignoreversion skipifsourcedoesntexist; Components: runtime +Source: "{#ComponentStagingDir}\configuration\cfg\ecaltime.ini"; DestDir: "{commonappdata}\eCAL\"; Flags: ignoreversion skipifsourcedoesntexist; Components: runtime + +; we need to change the location of these configuration file (as hotfix we use skipifsourcedoesntexist flag) +Source: "{#ComponentStagingDir}\_configuration\cfg\ecal.yaml"; DestDir: "{commonappdata}\eCAL\"; Tasks: not replaceconf; Flags: ignoreversion skipifsourcedoesntexist confirmoverwrite; Components: runtime +Source: "{#ComponentStagingDir}\_configuration\cfg\ecal.yaml"; DestDir: "{commonappdata}\eCAL\"; Tasks: replaceconf; Flags: ignoreversion skipifsourcedoesntexist; Components: runtime +Source: "{#ComponentStagingDir}\_configuration\cfg\ecaltime.ini"; DestDir: "{commonappdata}\eCAL\"; Flags: ignoreversion skipifsourcedoesntexist; Components: runtime ; applications Source: "{#ComponentStagingDir}\app\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: applications -Source: "{#ComponentStagingDir}\qwt_runtime\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: applications ; samples Source: "{#ComponentStagingDir}\samples\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: samples @@ -119,11 +124,17 @@ Source: "{#DebugSdkStagingDir}\protobuf-export\*"; DestDir: "{app}"; ; Source: "{#DebugSdkStagingDir}\protoc\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: sdk\protobuf ; sdk\hdf5 -Source: "{#ComponentStagingDir}\configinstall\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: sdk\hdf5 +; we need to change the location of these configuration file (as hotfix we use skipifsourcedoesntexist flag) +Source: "{#ComponentStagingDir}\configinstall\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist; Components: sdk\hdf5 +Source: "{#ComponentStagingDir}\_configinstall\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist; Components: sdk\hdf5 + Source: "{#ComponentStagingDir}\headers\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: sdk\hdf5 Source: "{#ComponentStagingDir}\libraries\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs; Components: sdk\hdf5 -Source: "{#DebugSdkStagingDir}\configinstall\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: sdk\hdf5 +; we need to change the location of these configuration file (as hotfix we use skipifsourcedoesntexist flag) +Source: "{#DebugSdkStagingDir}\configinstall\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist; Components: sdk\hdf5 +Source: "{#DebugSdkStagingDir}\_configinstall\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs skipifsourcedoesntexist; Components: sdk\hdf5 + Source: "{#DebugSdkStagingDir}\libraries\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs; Components: sdk\hdf5 Source: "{#DebugSdkStagingDir}\libraries\bin\*"; DestDir: "{app}\bin\"; Flags: ignoreversion recursesubdirs; Components: sdk\hdf5 @@ -133,7 +144,7 @@ Name: "{group}\eCAL Monitor"; Filename: "{app}\bin\ecal_ Name: "{group}\eCAL Recorder"; Filename: "{app}\bin\ecal_rec_gui.exe"; Components: applications Name: "{group}\eCAL Player"; Filename: "{app}\bin\ecal_play_gui.exe"; Components: applications Name: "{group}\eCAL Sys"; Filename: "{app}\bin\ecal_sys_gui.exe"; Components: applications -Name: "{group}\Configuration\Edit ecal.ini"; Filename: "{commonappdata}\eCAL\ecal.ini"; Components: runtime +Name: "{group}\Configuration\Edit ecal.yaml"; Filename: "{commonappdata}\eCAL\ecal.yaml"; Components: runtime Name: "{group}\{cm:UninstallProgram,{#AppName}}"; Filename: "{uninstallexe}" Name: "{commondesktop}\eCAL Launcher"; Filename: "{app}\bin\ecal_launcher.exe"; Tasks: desktopicon; Components: applications @@ -142,7 +153,6 @@ Name: "{commondesktop}\eCAL Launcher"; Filename: "{app}\bin\ecal_ ; Root key HKA is only available in Version 6 and above ; In Case of Non-Admin install mode, HKA will be resolved to HKCU, otherwise HKLM - see https://jrsoftware.org/ishelp/index.php?topic=setup_privilegesrequiredoverridesallowed Root: HKA; Subkey: {code:GetEnvironmentSubkey}; ValueType: string; ValueName: "ECAL_HOME"; ValueData: "{app}"; Flags: uninsdeletevalue; Components: applications -Root: HKA; Subkey: {code:GetEnvironmentSubkey}; ValueType: string; ValueName: "ECAL_DATA"; ValueData: "{commonappdata}\eCAL"; Flags: uninsdeletevalue; Components: applications Root: HKA; Subkey: "SOFTWARE\Classes\.ecalrec"; ValueType: string; ValueName: ""; ValueData: "ecal_rec_gui"; Flags: uninsdeletevalue; Components: applications Root: HKA; Subkey: "SOFTWARE\Classes\ecal_rec_gui"; ValueType: string; ValueName: ""; ValueData: "eCAL Recorder Configuration"; Flags: uninsdeletekey; Components: applications diff --git a/cpack/innosetup/gfx/NEURPOLI.TTF b/cpack/innosetup/gfx/NEURPOLI.TTF deleted file mode 100644 index 6db04ebc46..0000000000 Binary files a/cpack/innosetup/gfx/NEURPOLI.TTF and /dev/null differ diff --git a/doc/_static/css/bignums.css b/doc/_static/css/bignums.css new file mode 100644 index 0000000000..f4084cbd53 --- /dev/null +++ b/doc/_static/css/bignums.css @@ -0,0 +1,188 @@ +.bignums, +.bignums-hint, +.bignums-note, +.bignums-caution, +.bignums-warning, +.bignums-attention, +.bignums-important, +.bignums-seealso, +.bignums-tip, +.bignums-danger, +.bignums-error, +.bignums-xxl { + padding: 0; + counter-reset: li-counter +} + +.bignums>li, +.bignums-hint>li, +.bignums-note>li, +.bignums-caution>li, +.bignums-warning>li, +.bignums-attention>li, +.bignums-important>li, +.bignums-seealso>li, +.bignums-tip>li, +.bignums-danger>li, +.bignums-error>li, +.bignums-xxl>li { + list-style: none; + position: relative; + padding: 1rem; + padding-left: 3.875rem; + padding-top: 1.2875rem; + background-color: #e6e6e6; + min-height: 4.3rem; + border-radius: .25rem +} + +.bignums>li>.first, +.bignums-hint>li>.first, +.bignums-note>li>.first, +.bignums-caution>li>.first, +.bignums-warning>li>.first, +.bignums-attention>li>.first, +.bignums-important>li>.first, +.bignums-seealso>li>.first, +.bignums-tip>li>.first, +.bignums-danger>li>.first, +.bignums-error>li>.first, +.bignums-xxl>li>.first { + font-weight: 600; + font-size: 1.15rem +} + +.bignums>li *:last-child, +.bignums-hint>li *:last-child, +.bignums-note>li *:last-child, +.bignums-caution>li *:last-child, +.bignums-warning>li *:last-child, +.bignums-attention>li *:last-child, +.bignums-important>li *:last-child, +.bignums-seealso>li *:last-child, +.bignums-tip>li *:last-child, +.bignums-danger>li *:last-child, +.bignums-error>li *:last-child, +.bignums-xxl>li *:last-child { + margin-bottom: 0 +} + +.bignums>li:before, +.bignums-hint>li:before, +.bignums-note>li:before, +.bignums-caution>li:before, +.bignums-warning>li:before, +.bignums-attention>li:before, +.bignums-important>li:before, +.bignums-seealso>li:before, +.bignums-tip>li:before, +.bignums-danger>li:before, +.bignums-error>li:before, +.bignums-xxl>li:before { + font-size: 1.15rem; + display: block; + position: absolute; + top: 1rem; + left: 1rem; + height: 2em; + width: 2em; + line-height: 2em; + text-align: center; + background-color: #313131; + color: #fff; + border-radius: 50%; + content: counter(li-counter, decimal); + counter-increment: li-counter; + font-weight: 600 +} + +.bignums>li+li, +.bignums-hint>li+li, +.bignums-note>li+li, +.bignums-caution>li+li, +.bignums-warning>li+li, +.bignums-attention>li+li, +.bignums-important>li+li, +.bignums-seealso>li+li, +.bignums-tip>li+li, +.bignums-danger>li+li, +.bignums-error>li+li, +.bignums-xxl>li+li { + margin-top: 1rem +} + +.bignums-hint>li, +.bignums-note>li { + background-color: #ebf7fb +} + +.bignums-hint>li:before, +.bignums-note>li:before { + background-color: #5bc0de; + color: #212121 +} + +.bignums-caution>li, +.bignums-warning>li, +.bignums-attention>li { + background-color: #fdf5ea +} + +.bignums-caution>li:before, +.bignums-warning>li:before, +.bignums-attention>li:before { + background-color: #f0ad4e; + color: #212121 +} + +.bignums-important>li, +.bignums-seealso>li, +.bignums-tip>li { + background-color: #ebf6eb +} + +.bignums-important>li:before, +.bignums-seealso>li:before, +.bignums-tip>li:before { + background-color: #5cb85c; + color: #fff +} + +.bignums-danger>li, +.bignums-error>li { + background-color: #faeaea +} + +.bignums-danger>li:before, +.bignums-error>li:before { + background-color: #d9534f; + color: #fff +} + +.bignums-xxl>li { + padding: 0; + padding-left: 3.75rem; + padding-top: .375rem; + background-color: transparent; + min-height: 3rem +} + +.bignums-xxl>li>.first { + font-size: 1.5rem +} + +.bignums-xxl>li:before { + font-size: 1.5rem; + top: 0; + left: 0 +} + +.bignums-xxl>li+li { + border-top: 1px solid rgba(0, 0, 0, 0.15); + margin-top: 1.375rem; + padding-top: 1.375rem +} + +.bignums-xxl>li+li:before { + top: 1rem +} \ No newline at end of file diff --git a/doc/_static/css/sphinx-book-theme-1.1.2-ecaladdon.css b/doc/_static/css/sphinx-book-theme-1.1.2-ecaladdon.css new file mode 100644 index 0000000000..0ff1c1d2c1 --- /dev/null +++ b/doc/_static/css/sphinx-book-theme-1.1.2-ecaladdon.css @@ -0,0 +1,12 @@ +html[data-theme=dark], +html[data-theme=light] { + --pst-color-primary: #ffa500; +} + +html[data-theme=light] { + --pst-color-secondary: #CC8400; +} + +html[data-theme=dark] { + --pst-color-secondary: #FFC04D; +} \ No newline at end of file diff --git a/doc/_static/css/tabs-3.4.5-ecaladdon.css b/doc/_static/css/tabs-3.4.5-ecaladdon.css new file mode 100644 index 0000000000..07065503ea --- /dev/null +++ b/doc/_static/css/tabs-3.4.5-ecaladdon.css @@ -0,0 +1,93 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0a0a0; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: var(--pst-color-muted); + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: var(--pst-color-background); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0a0a0; + border-bottom: 1px solid var(--pst-color-background); + margin: -1px; + background-color: var(--pst-color-background); + + box-shadow: 0 9px 0px -1px var(--pst-color-background), 0 3px 3px 0 var(--pst-color-shadow); +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0a0a0; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: var(--pst-color-background); + + box-shadow: 0 3px 3px 0px var(--pst-color-shadow); +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/doc/_static/img/ecal-logo.svg b/doc/_static/img/ecal-logo.svg new file mode 100644 index 0000000000..3dd4b18c12 --- /dev/null +++ b/doc/_static/img/ecal-logo.svg @@ -0,0 +1,214 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/img/favicon.png b/doc/_static/img/favicon.png new file mode 100644 index 0000000000..fe298c679a Binary files /dev/null and b/doc/_static/img/favicon.png differ diff --git a/doc/_templates/footer.html b/doc/_templates/footer.html new file mode 100644 index 0000000000..447ca399ff --- /dev/null +++ b/doc/_templates/footer.html @@ -0,0 +1,26 @@ + + + diff --git a/doc/extensions/generate_download_tables.py b/doc/extensions/generate_download_tables.py index a2bb0fb24c..834d14376e 100644 --- a/doc/extensions/generate_download_tables.py +++ b/doc/extensions/generate_download_tables.py @@ -15,6 +15,7 @@ semantic_version.Version("18.4.0"): semantic_version.Version("3.6.0"), semantic_version.Version("20.4.0"): semantic_version.Version("3.8.0"), semantic_version.Version("22.4.0"): semantic_version.Version("3.10.0"), + semantic_version.Version("24.4.0"): semantic_version.Version("3.12.0"), } ubuntu_codename_dict = \ diff --git a/doc/extensions/generate_release_page.py b/doc/extensions/generate_release_page.py new file mode 100644 index 0000000000..48ca6a4a23 --- /dev/null +++ b/doc/extensions/generate_release_page.py @@ -0,0 +1,431 @@ +import os + +import sys +import re +import github +import jinja2 +import semantic_version +from collections import OrderedDict + +ubuntu_default_python_version_dict = \ +{ + semantic_version.Version("18.4.0"): semantic_version.Version("3.6.0"), + semantic_version.Version("20.4.0"): semantic_version.Version("3.8.0"), + semantic_version.Version("22.4.0"): semantic_version.Version("3.10.0"), + semantic_version.Version("24.4.0"): semantic_version.Version("3.12.0"), +} + +ubuntu_codename_dict = \ +{ + "noble": semantic_version.Version("24.4.0"), + "jammy": semantic_version.Version("22.4.0"), + "focal": semantic_version.Version("20.4.0"), + "bionic": semantic_version.Version("18.4.0"), + "xenial": semantic_version.Version("16.4.0"), + "trusty": semantic_version.Version("14.4.0"), +} + +""" +Retrieves a dictionary of release branches and their corresponding releases from the GitHub repository. +Args: + gh_repo (github.Github): An authenticated GitHub instance. +Returns: + dict: A dictionary where the keys are minor relase numbers (-> patch level + set to 0) and Values are Dictionaries of + {specific_release : gh_release_object} +Example: + { + Version('5.8.0'): { + Version('5.8.0'): , + Version('5.8.1'): + }, + Version('5.9.0'): { + Version('5.9.0'): + } + } +""" +def get_releases_dict(gh_repo): + gh_releases = gh_repo.get_releases() + + gh_release_branches_dict = OrderedDict() + + for gh_release in gh_releases: + if gh_release.prerelease or gh_release.draft: + continue + + version_string = gh_release.tag_name + + if version_string.startswith("v") or version_string.startswith("V"): + version_string = version_string[1:] + if version_string.startswith("."): + version_string = version_string[1:] + + # Fix format, so it can be parsed by semantic_version: + dot_components = version_string.split(".") + if len(dot_components) == 4: + version_string = '.'.join(dot_components[:-1]) + "+" + dot_components[3] + elif len(dot_components) == 5: + version_string = '.'.join(dot_components[:-2]) + "-" + dot_components[3] + "+" + dot_components[4] + + try: + version = semantic_version.Version(version_string) + except: + sys.stderr.write("Warning: eCAL Release \"" + gh_release.tag_name + "\" is not parsable to a proper version.\n") + continue + + version = semantic_version.Version(version_string) + release_branch = semantic_version.Version(major = version.major, minor = version.minor, patch = 0) + + if not release_branch in gh_release_branches_dict: + # Initialize dicitonary for this branch + gh_release_branches_dict[release_branch] = OrderedDict() + + gh_release_branches_dict[release_branch][version] = gh_release + + # Sort the minor eCAL Release branches by version + gh_release_branches_dict = OrderedDict(sorted(gh_release_branches_dict.items(), key = lambda x: x[0], reverse = True)) + + # Sort the specific releases by version + for release_branch in gh_release_branches_dict: + gh_release_branches_dict[release_branch] = OrderedDict(sorted(gh_release_branches_dict[release_branch].items(), key = lambda x: x[0], reverse = True)) + + return gh_release_branches_dict + +""" +Retrieves the properties of a given GitHub asset. + +Args: + ecal_version (semantic_version.Version): The version of eCAL. + gh_asset (github.Asset): The GitHub asset object. + +Returns: + dict: A dictionary containing the properties of the asset, including: + + { + 'filename' : 'actual filename', + 'download_link': 'browser download link', + 'type' : 'source / ecal_installer / python_binding', + 'properties' : SEE BELOW, + } + + Properties for "source": + {} + + Properties for "ecal_installer": + { + 'os': 'windows / macos / ubuntu', + 'os_version': Semver('0.0.0') (Only for Ubuntu specific installers), + 'cpu': 'amd64 / arm64' + } + + Properties for "python_binding": + { + 'os': 'manylinux / macos / windows / ubuntu', + 'os_version': Semver('0.0.0') (Only for Ubuntu specific bindings), + 'cpu': 'amd64 / arm64', + 'python_version': Semver('3.6.0') (example) + 'python_implementation': 'cp / pp etc.' (i.e. CPython or PyPy) + } +""" +def get_asset_properties(ecal_version, gh_asset): + asset_properties = { + 'filename' : '', + 'download_link': '', + 'type' : '', + 'properties' : {}, + } + + asset_properties['filename'] = gh_asset.name + asset_properties['download_link'] = gh_asset.browser_download_url + + # Source + if asset_properties['filename'].endswith('tar.gz'): + asset_properties['type'] = 'source' + + # eCAL Installer for Windows + elif asset_properties['filename'].endswith('.msi') or asset_properties['filename'].endswith('.exe'): + asset_properties['type'] = 'ecal_installer' + asset_properties['properties']['os'] = 'windows' + asset_properties['properties']['cpu'] = 'amd64' + + # eCAL installer for macOS + elif asset_properties['filename'].endswith('.dmg'): + asset_properties['type'] = 'ecal_installer' + asset_properties['properties']['os'] = 'macos' + asset_properties['properties']['cpu'] = 'amd64' + + # eCAL Installer for Linux + elif asset_properties['filename'].endswith('.deb'): + asset_properties['type'] = 'ecal_installer' + asset_properties['properties']['os'] = 'ubuntu' + asset_properties['properties']['os_version'] = semantic_version.Version('0.0.0') + asset_properties['properties']['cpu'] = 'amd64' + + if ecal_version <= semantic_version.Version("5.7.2"): + # Special case for old releases. They only had Ubuntu 20.04 releases that were just named "linux". + asset_properties['properties']['os_version'] = semantic_version.Version("20.4.0") + else: + for codename, version in ubuntu_codename_dict.items(): + if codename in asset_properties['filename']: + asset_properties['properties']['os_version'] = version + break + + if ecal_version <= semantic_version.Version("5.7.2"): + # Special case for old releases. They only had Ubuntu 20.04 releases that were just named "linux". + asset_properties['properties']['os_version'] = semantic_version.Version("20.4.0") + + # Python binding (whl) + elif asset_properties['filename'].endswith('.whl'): + asset_properties['type'] = 'python_binding' + + # Get Operating system + if 'manylinux' in asset_properties['filename']: + asset_properties['properties']['os'] = 'manylinux' + elif 'darwin' in asset_properties['filename'] or 'macos' in asset_properties['filename']: + asset_properties['properties']['os'] = 'macos' + elif "win64" in asset_properties['filename'] or "win_amd64" in asset_properties['filename']: + asset_properties['properties']['os'] = 'windows' + elif 'linux' in asset_properties['filename']: + # Old eCAL 5.x wheels were Ubuntu specific + asset_properties['properties']['os'] = 'ubuntu' + for codename, version in ubuntu_codename_dict.items(): + if codename in asset_properties['filename']: + asset_properties['properties']['os_version'] = version + break + else: + sys.stderr.write("Warning: Unable to determine OS of python binding: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + # Get Python CPU Architecture + filename_without_extension = os.path.splitext(asset_properties['filename'])[0] + if filename_without_extension.endswith('amd64') or filename_without_extension.endswith('x86_64') or filename_without_extension.endswith('win64'): + asset_properties['properties']['cpu'] = 'amd64' + elif filename_without_extension.endswith('arm64') or filename_without_extension.endswith('aarch64'): + asset_properties['properties']['cpu'] = 'arm64' + else: + sys.stderr.write("Warning: Unable to determine CPU Architecture of python binding: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + # Get Python version + python_version = semantic_version.Version("0.0.0") + python_implementation = '' + components = asset_properties['filename'][:-4].split('-') + # The python version is either index 2 or 3, depending on whether the optional build tag is used. + for index in range(2,4): + if re.match(r"[a-z]{2}[0-9]+", components[index]): + python_implementation = components[index][:2] + python_version_major_string = components[index][2] + python_verstion_minor_string = "0" + if len(components[index]) > 3: + python_verstion_minor_string = components[index][3:] + python_version = semantic_version.Version(python_version_major_string + "." + python_verstion_minor_string + ".0") + break + + if python_version == semantic_version.Version("0.0.0"): + sys.stderr.write("Warning: Unable to determine python version: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + if not python_implementation: + sys.stderr.write("Warning: Unable to determine python implementation: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + asset_properties['properties']['python_version'] = python_version + asset_properties['properties']['python_implementation'] = python_implementation + + # Python binding (.egg) + elif asset_properties['filename'].endswith('.egg'): + asset_properties['type'] = 'python_binding' + + # Get Operating system + if 'darwin' in asset_properties['filename'] or 'macos' in asset_properties['filename']: + asset_properties['properties']['os'] = 'macos' + elif "win64" in asset_properties['filename'] or "win_amd64" in asset_properties['filename']: + asset_properties['properties']['os'] = 'windows' + elif 'linux' in asset_properties['filename'] or 'bionic' in asset_properties['filename'] or 'focal' in asset_properties['filename']: + asset_properties['properties']['os'] = 'ubuntu' + if ecal_version <= semantic_version.Version("5.7.2"): + # Special case for old releases. They only had Ubuntu 20.04 releases that were just named "linux". + asset_properties['properties']['os_version'] = semantic_version.Version("20.4.0") + else: + for codename, version in ubuntu_codename_dict.items(): + if codename in asset_properties['filename']: + asset_properties['properties']['os_version'] = version + break + + if not asset_properties['properties'].get('os'): + sys.stderr.write("Warning: Unable to determine OS of python binding: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + # Get python version + python_version = semantic_version.Version("0.0.0") + python_match_result = re.findall(r"py[0-9]+\.[0-9]+", asset_properties['filename']) + if len(python_match_result) > 0: + python_version = semantic_version.Version(python_match_result[0][2:] + ".0") + + if python_version == semantic_version.Version("0.0.0"): + sys.stderr.write("Warning: Unable to determine python version: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + asset_properties['properties']['python_version'] = python_version + asset_properties['properties']['python_implementation'] = 'cp' # The eggs were all CPython + + # CPU Architecture was always amd64 back then + asset_properties['properties']['cpu'] = 'amd64' + + # Warning, as we have no idea what this file is for + else: + sys.stderr.write("Warning: Unknown asset type: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + return asset_properties + +def generate_release_index_page(releases_dict, list_of_supported_minor_versions, output_filename): + # Create the output directory if it does not exist + output_dir = os.path.dirname(output_filename) + if output_dir and not os.path.exists(output_dir): + os.makedirs(output_dir) + + # Load the Jinja2 template + template_loader = jinja2.FileSystemLoader(searchpath="resource/") + template_env = jinja2.Environment(loader=template_loader) + template_file = "release_page_index.rst.jinja" + template = template_env.get_template(template_file) + + # Render the template with the context + context = { + 'releases_dict': releases_dict, + 'list_of_supported_minor_versions': list_of_supported_minor_versions, + 'group_asset_list_by_os_and_arch': group_asset_list_by_os_and_arch, + 'get_rst_release_page_label': get_rst_release_page_label, + } + output = template.render(context) + + # Save the rendered template to a file + with open(output_filename, "w") as f: + f.write(output) + +def generate_release_page(gh_release, + ecal_version, + asset_list, + minor_is_supported, + latest_version_of_minor, + output_dir): + ecal_version_string = str(ecal_version).replace('.', '_').replace('-', '_').replace('+', '_') + output_filename = "ecal_" + ecal_version_string + ".rst" + changelog_file = "changelog_ecal_" + ecal_version_string + ".txt" + + # Create the output directory if it does not exist + if output_dir and not os.path.exists(output_dir): + os.makedirs(output_dir) + + # Save the changelog to a file + changelog = gh_release.body + changelog = changelog.replace('\r\n', '\n') + with open(os.path.join(output_dir, changelog_file), "w") as f: + f.write(changelog) + + # Load the Jinja2 template + template_loader = jinja2.FileSystemLoader(searchpath="resource/") + template_env = jinja2.Environment(loader=template_loader) + template_file = "release_page.rst.jinja" + template = template_env.get_template(template_file) + + # Render the template with the context + context = { + 'gh_release': gh_release, + 'ecal_version': ecal_version, + 'asset_list': asset_list, + 'changelog_file_path': changelog_file, + 'minor_is_supported': minor_is_supported, + 'latest_version_of_minor': latest_version_of_minor, + 'ubuntu_default_python_version_dict': ubuntu_default_python_version_dict, + 'group_asset_list_by_os_and_arch': group_asset_list_by_os_and_arch, + 'get_rst_release_page_label': get_rst_release_page_label, + } + output = template.render(context) + + # Save the rendered template to a file + path = os.path.join(output_dir, output_filename) + with open(path, "w") as f: + f.write(output) + +""" +Groups a list of assets by their OS, OS version, and CPU architecture. +Args: + asset_list (list): A list of asset properties dictionaries. +Returns: + dict: A dictionary where the keys are tuples of (os, os_version, cpu) and + the values are lists of asset properties dictionaries. +""" +def group_asset_list_by_os_and_arch(asset_list): + os_arch_dict = OrderedDict() + + for asset_properties in asset_list: + os = asset_properties['properties'].get('os', 'unknown') + os_version = asset_properties['properties'].get('os_version', semantic_version.Version('0.0.0')) + cpu = asset_properties['properties'].get('cpu', 'unknown') + + key = (os, os_version, cpu) + if key not in os_arch_dict: + os_arch_dict[key] = [] + os_arch_dict[key].append(asset_properties) + + return os_arch_dict + +def get_rst_release_page_label(ecal_version): + return "ecal_release_page_" + str(ecal_version).replace('.', '_').replace('-', '_').replace('+', '_') + +def generate_release_documentation(gh_api_key, index_filepath, release_dir_path): + gh = github.Github(gh_api_key) + gh_repo = gh.get_repo("eclipse-ecal/ecal") + releases_dict = get_releases_dict(gh_repo) + + list_of_supported_minor_versions = list(releases_dict.keys())[:2] + + generate_release_index_page(releases_dict, + list_of_supported_minor_versions, + index_filepath) + + for minor_version in releases_dict: + + # Get the latest eCAL Version of this release branch + latest_release_for_this_minor = list(releases_dict[minor_version].keys())[0] + this_minor_is_supported = minor_version in list_of_supported_minor_versions + + for ecal_version in releases_dict[minor_version]: + + # Check the support status of this release + + gh_release = releases_dict[minor_version][ecal_version] + gh_asset_list = gh_release.get_assets() + + asset_list = [] + + for gh_asset in gh_asset_list: + asset_properties = get_asset_properties(ecal_version, gh_asset) + asset_list.append(asset_properties) + + # Sort the asset list by: + # 1. OS (windows > manylinux > ubuntu > macos) + # 2. OS version (descending) + # 3. CPU (amd64 > arm64) + # 4. Python version (descending) + + asset_list.sort(key = lambda x: x['properties'].get('python_version', semantic_version.Version("0.0.0")), reverse = True) + asset_list.sort(key = lambda x: x['properties'].get('os_version', semantic_version.Version("0.0.0")), reverse = True) + asset_list.sort(key = lambda x: x['properties'].get('cpu', 'unknown')) + asset_list.sort(key = lambda x: ['windows', 'manylinux', 'ubuntu', 'macos'].index(x['properties'].get('os', 'unknown')) if x['properties'].get('os', 'unknown') in ['windows', 'manylinux', 'ubuntu', 'macos'] else float('inf')) + + generate_release_page(gh_release, + ecal_version, + asset_list, + this_minor_is_supported, + latest_release_for_this_minor, + release_dir_path) + +if __name__=="__main__": + gh_api_key = os.getenv("ECAL_GH_API_KEY") + if gh_api_key: + generate_release_documentation(gh_api_key, "index.rst", "release") + else: + sys.stderr.write("ERROR: Environment variable ECAL_GH_API_KEY not set. Without an API key, GitHub will not provide enough API calls to generate the download tables.\n") + exit(1) + + + + + + + diff --git a/doc/extensions/resource/release_page.rst.jinja b/doc/extensions/resource/release_page.rst.jinja new file mode 100644 index 0000000000..4411a39b01 --- /dev/null +++ b/doc/extensions/resource/release_page.rst.jinja @@ -0,0 +1,206 @@ +{% set ecal_version_string = ecal_version | string -%} + +{# Makro for properly naming the OS, possibly with icon. e.g. "|fa-windows| Windows" (-> capitalized) or |fa-ubuntu| Ubuntu 24.04 (-> with Version number) -#} +{% macro get_os_string(asset, with_icon) -%} + {% if asset['properties']['os'] == 'windows' -%} + {% set os_string = (with_icon and '|fa-windows| ' or '') ~ 'Windows' -%} + {% elif asset['properties']['os'] == 'macos' -%} + {% set os_string = (with_icon and '|fa-apple| ' or '') ~ 'macOS' -%} + {% elif asset['properties']['os'] == 'ubuntu' -%} + {% set os_version_padded = asset['properties']['os_version'].major ~ '.' ~ '%02d' | format(asset['properties']['os_version'].minor) -%} + {% set os_string = (with_icon and '|fa-Ubuntu| ' or '') ~ 'Ubuntu ' ~ os_version_padded -%} + {% elif asset['properties']['os'] == 'manylinux' -%} + {% set os_string = (with_icon and '|fa-linux| ' or '') ~ 'Linux (All)' -%} + {% elif asset['properties']['os'] == '' -%} + {% set os_string = 'Unknown' -%} + {% else -%} + {% set os_string = asset['properties']['os'].capitalize() -%} + {% endif -%} + {{ os_string -}} +{% endmacro -%} + +{# Makro for naming the CPU Architecture. Mainly to make amd64 to x64, so the user can more easily distinguish it from arm64 #} +{% macro get_cpu_string(asset) -%} + {% if asset['properties']['cpu'] == 'amd64' -%} + {% set cpu_string = 'x64' -%} + {% elif asset['properties']['cpu'] == 'arm64' -%} + {% set cpu_string = 'ARM64' -%} + {% else -%} + {% set cpu_string = asset['properties']['cpu'] -%} + {% endif -%} + {{ cpu_string -}} +{% endmacro -%} +:orphan: + +.. include:: /../include.txt + +.. _{{ get_rst_release_page_label(ecal_version) }}: + +=============== +eCAL {{ ecal_version_string }} +=============== + +{% if not minor_is_supported %} +.. warning:: + + eCAL {{ ecal_version.major }}.{{ ecal_version.minor }} is not supported anymore. Please consider upgrading to a newer version. +{% endif %} + +- Release Date: {{ gh_release.published_at.strftime('%Y-%m-%d') }} +- GitHub Release Page: {{ gh_release.html_url }} + +Changelog +========= + +.. literalinclude:: {{ changelog_file_path }} + :language: text + +Downloads +========= + +{% if ecal_version < latest_version_of_minor %} +.. note:: + + A more recent version of eCAL {{ ecal_version.major }}.{{ ecal_version.minor }} is available: :ref:`eCAL {{ latest_version_of_minor }} <{{ get_rst_release_page_label(latest_version_of_minor) }}>`. +{% endif %} + +{# Get the ecal_installers from the list and remove them from the main list. -#} +{% set ecal_installer_list = asset_list | selectattr('type', 'equalto', 'ecal_installer') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'ecal_installer') | list -%} + +{% if ecal_installer_list %} +eCAL Installer +-------------- + +.. list-table:: + :widths: 2 2 6 + :header-rows: 1 + + * - OS + + - Architecture + + - Files + + {% for asset in ecal_installer_list -%} + + * - {{ get_os_string(asset, true) }} + + - {{ get_cpu_string(asset) }} + + - `{{ asset['filename'] }} <{{ asset['download_link'] }}>`__ + + {% endfor -%} + +{% endif -%} + +{# Get the python bindings from the list -#} +{% set python_binding_list = asset_list | selectattr('type', 'equalto', 'python_binding') | selectattr('properties.python_implementation', 'equalto', 'cp') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'python_binding') | list -%} + +{% if python_binding_list %} +|fa-python| Python Binding +-------------------------- + +.. list-table:: + :widths: 2 2 6 + :header-rows: 1 + + * - OS + + - Architecture + + - Files + + {% set python_binding_grouped_dict = group_asset_list_by_os_and_arch(python_binding_list) -%} + + {% for key, value in python_binding_grouped_dict.items() -%} + {% if value[0]['properties']['os'] == 'ubuntu' -%} + {% set default_python_version = ubuntu_default_python_version_dict[value[0]['properties']['os_version']] -%} + {% endif %} + * - {{ get_os_string(value[0], true) }} + + - {{ get_cpu_string(value[0]) }} + + - {% for asset in value -%} + `Python {{ asset['properties']['python_version'].major }}.{{ asset['properties']['python_version'].minor }} (.{{ asset['filename'].split('.')[-1] }}) <{{ asset['download_link'] }}>`__ {% if asset['properties']['python_version'] == default_python_version %} (Default){% endif %} + + {% endfor -%} + + {% endfor -%} + +{% endif -%} + +{# Get the PyPy bindings from the list -#} +{% set pypy_binding_list = asset_list | selectattr('type', 'equalto', 'python_binding') | selectattr('properties.python_implementation', 'equalto', 'pp') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'python_binding') | list -%} + +{% if pypy_binding_list %} +|fa-python| PyPy Binding +------------------------ + +*PyPy bindings are not compatibly with the regular Python implementation.* + +.. list-table:: + :widths: 2 2 6 + :header-rows: 1 + + * - OS + + - Architecture + + - Files + + {% set pypy_binding_grouped_dict = group_asset_list_by_os_and_arch(pypy_binding_list) -%} + + {% for key, value in pypy_binding_grouped_dict.items() %} + * - {{ get_os_string(value[0], true) }} + + - {{ get_cpu_string(value[0]) }} + + - {% for asset in value -%} + `PyPy {{ asset['properties']['python_version'].major }}.{{ asset['properties']['python_version'].minor }} (.{{ asset['filename'].split('.')[-1] }}) <{{ asset['download_link'] }}>`__ + + {% endfor -%} + + {% endfor -%} + +{% endif -%} + +{# Get the source files from the list -#} +{% set source_file_list = asset_list | selectattr('type', 'equalto', 'source') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'source') | list -%} + +{% if source_file_list %} +|fa-code| Source +---------------- + +.. list-table:: + :widths: 1 + + {% for asset in source_file_list -%} + + * - `{{ asset['filename'] }} <{{ asset['download_link'] }}>`__ + + {% endfor -%} + +{% endif %} + +{# Get the other files from the list -#} +{% if asset_list %} +Other Downloads +--------------- + +.. list-table:: + :widths: 1 + :header-rows: 1 + + * - Files + + {% for asset in asset_list -%} + + * - `{{ asset['filename'] }} <{{ asset['download_link'] }}>`__ + + {% endfor -%} + +{% endif -%} \ No newline at end of file diff --git a/doc/extensions/resource/release_page_index.rst.jinja b/doc/extensions/resource/release_page_index.rst.jinja new file mode 100644 index 0000000000..4b3deac6b5 --- /dev/null +++ b/doc/extensions/resource/release_page_index.rst.jinja @@ -0,0 +1,44 @@ +.. include:: /../include.txt + +.. _all_releases: + +============ +All releases +============ + +Here you can find a list of all eCAL Versions ever released on GitHub. + +{% for minor_version, releases_dict in releases_dict.items() %} +eCAL {{ minor_version.major }}.{{ minor_version.minor }} +=========== + +{% if minor_version not in list_of_supported_minor_versions -%} + +*eCAL {{ minor_version.major }}.{{ minor_version.minor }} has reached its end of life.* + +{% endif -%} + +.. list-table:: + :widths: 3 3 4 + :header-rows: 1 + + * - Release + + - Release Date + + - Support Status + +{% for ecal_version, gh_release in releases_dict.items() -%} +{% set is_latest_release_in_this_minor = (ecal_version == releases_dict.keys()|list|first) %} + * - :ref:`eCAL {{ gh_release.tag_name }} <{{ get_rst_release_page_label(ecal_version) }}>` + + - {{ gh_release.published_at.strftime("%Y-%m-%d") }} + + - {% if (minor_version in list_of_supported_minor_versions) and is_latest_release_in_this_minor -%} + Supported + {% else -%} + EOL + {% endif -%} +{% endfor -%} + +{% endfor -%} \ No newline at end of file diff --git a/doc/include.txt b/doc/include.txt new file mode 100644 index 0000000000..0907e80e11 --- /dev/null +++ b/doc/include.txt @@ -0,0 +1,78 @@ + +.. |fa-windows| raw:: html + + + +.. |fa-linux| raw:: html + + + +.. |fa-ubuntu| raw:: html + + + +.. |fa-apple| raw:: html + + + +.. |fa-folder-open| raw:: html + + + +.. |fa-folder| raw:: html + + + +.. |fa-file| raw:: html + + + +.. |fa-file-alt| raw:: html + + + +.. |fa-download| raw:: html + + + +.. |fa-github| raw:: html + + + +.. |fa-book| raw:: html + + + +.. |fa-copy| raw:: html + + + +.. |fa-python| raw:: html + + + +.. |fa-pencil-alt| raw:: html + + + +.. |fa-code| raw:: html + + + + +.. |ecalini-path-windows| replace:: :file:`C:\\ProgramData\\eCAL\\ecal.yaml` +.. |ecalini-path-ubuntu| replace:: :file:`/etc/ecal/ecal.yaml` + +.. |ecalini-path-windows-old| replace:: :file:`C:\\eCAL\\cfg\\ecal.yaml` +.. |ecalini-path-ubuntu-old| replace:: :file:`/usr/etc/ecal/ecal.yaml` + + +.. |person_snd-path-windows| replace:: :file:`C:\\eCAL\\samples\\bin\\ecal_sample_person_snd.exe` +.. |person_rec-path-windows| replace:: :file:`C:\\eCAL\\samples\\bin\\ecal_sample_person_rec.exe` +.. |service_server_c-path-windows| replace:: :file:`C:\\eCAL\\samples\\bin\\ecal_sample_minimal_server_c.exe` +.. |service_client_c-pathwindows| replace:: :file:`C:\\eCAL\\samples\\bin\\ecal_sample_minimal_client_c.exe` + +.. |ecal_mon-start-menu-path-windows| replace:: :file:`Start / eCAL / eCAL Monitor` +.. |ecal_rec-start-menu-path-windows| replace:: :file:`Start / eCAL / eCAL Recorder` +.. |ecal_play-start-menu-path-windows| replace:: :file:`Start / eCAL / eCAL Player` +.. |ecal_sys-start-menu-path-windows| replace:: :file:`Start / eCAL / eCAL Sys` diff --git a/doc/release_page/conf.py b/doc/release_page/conf.py new file mode 100644 index 0000000000..4c6132a61b --- /dev/null +++ b/doc/release_page/conf.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +import os +import sys + +# -- Generate download archive and tables for the homepage -------------------- +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import generate_release_documentation + +gh_api_key = os.getenv("ECAL_GH_API_KEY") +if gh_api_key: + release_page_dir = "." + index_file_path = "./index.rst" + generate_release_documentation.generate_release_documentation(gh_api_key, index_file_path, release_page_dir) +else: + print("ERROR: Environment variable ECAL_GH_API_KEY not set. Skipping generating download tables.") + exit(1) + +# -- Project information ----------------------------------------------------- + +project = u'Eclipse eCAL™' +copyright = u'2023, Continental' +#author = u'Continental' + +# The short X.Y version +# version = u'' +# The full version, including alpha/beta/rc tags +# release = u'' + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx_book_theme', + 'sphinx_tabs.tabs', + 'sphinx.ext.githubpages', +] + +# Tell sphinx what the primary language being documented is. +#primary_domain = 'cpp' + +# Tell sphinx what the pygments highlight language should be. +#highlight_language = 'cpp' + + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['../_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +# pygments_style = 'sphinx' + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_book_theme' + + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['../_static'] + +html_css_files = [ + 'css/bignums.css', # Enable the bignum feature from the sphinx-typo3-theme + 'css/sphinx-book-theme-1.1.2-ecaladdon.css', # Change colors of the sphinx-book-theme + 'css/tabs-3.4.5-ecaladdon.css', # Change colors of the sphinx-tabs +] + +html_title = "Eclipse eCAL™" +html_logo = "../_static/img/ecal-logo.svg" +html_favicon = "../_static/img/favicon.png" + +html_theme_options = { + "logo_only": True, + "show_navbar_depth": 1, + "show_toc_level": 2, + "repository_url": "https://github.com/eclipse-ecal/ecal/", + "use_repository_button": False, + "use_issues_button": False, + "use_edit_page_button": False, + "repository_branch": "master", + "path_to_docs": "doc/rst/", + "extra_navbar": "", # => Remove the default text + "footer_start": ["footer.html"], + "extra_footer": '', +} + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'eCALdoc' + +# C++ defines used in function definitions +cpp_id_attributes = ['ECAL_API', 'ECALTIME_API'] diff --git a/doc/release_page/generate_release_documentation/__init__.py b/doc/release_page/generate_release_documentation/__init__.py new file mode 100644 index 0000000000..48ca6a4a23 --- /dev/null +++ b/doc/release_page/generate_release_documentation/__init__.py @@ -0,0 +1,431 @@ +import os + +import sys +import re +import github +import jinja2 +import semantic_version +from collections import OrderedDict + +ubuntu_default_python_version_dict = \ +{ + semantic_version.Version("18.4.0"): semantic_version.Version("3.6.0"), + semantic_version.Version("20.4.0"): semantic_version.Version("3.8.0"), + semantic_version.Version("22.4.0"): semantic_version.Version("3.10.0"), + semantic_version.Version("24.4.0"): semantic_version.Version("3.12.0"), +} + +ubuntu_codename_dict = \ +{ + "noble": semantic_version.Version("24.4.0"), + "jammy": semantic_version.Version("22.4.0"), + "focal": semantic_version.Version("20.4.0"), + "bionic": semantic_version.Version("18.4.0"), + "xenial": semantic_version.Version("16.4.0"), + "trusty": semantic_version.Version("14.4.0"), +} + +""" +Retrieves a dictionary of release branches and their corresponding releases from the GitHub repository. +Args: + gh_repo (github.Github): An authenticated GitHub instance. +Returns: + dict: A dictionary where the keys are minor relase numbers (-> patch level + set to 0) and Values are Dictionaries of + {specific_release : gh_release_object} +Example: + { + Version('5.8.0'): { + Version('5.8.0'): , + Version('5.8.1'): + }, + Version('5.9.0'): { + Version('5.9.0'): + } + } +""" +def get_releases_dict(gh_repo): + gh_releases = gh_repo.get_releases() + + gh_release_branches_dict = OrderedDict() + + for gh_release in gh_releases: + if gh_release.prerelease or gh_release.draft: + continue + + version_string = gh_release.tag_name + + if version_string.startswith("v") or version_string.startswith("V"): + version_string = version_string[1:] + if version_string.startswith("."): + version_string = version_string[1:] + + # Fix format, so it can be parsed by semantic_version: + dot_components = version_string.split(".") + if len(dot_components) == 4: + version_string = '.'.join(dot_components[:-1]) + "+" + dot_components[3] + elif len(dot_components) == 5: + version_string = '.'.join(dot_components[:-2]) + "-" + dot_components[3] + "+" + dot_components[4] + + try: + version = semantic_version.Version(version_string) + except: + sys.stderr.write("Warning: eCAL Release \"" + gh_release.tag_name + "\" is not parsable to a proper version.\n") + continue + + version = semantic_version.Version(version_string) + release_branch = semantic_version.Version(major = version.major, minor = version.minor, patch = 0) + + if not release_branch in gh_release_branches_dict: + # Initialize dicitonary for this branch + gh_release_branches_dict[release_branch] = OrderedDict() + + gh_release_branches_dict[release_branch][version] = gh_release + + # Sort the minor eCAL Release branches by version + gh_release_branches_dict = OrderedDict(sorted(gh_release_branches_dict.items(), key = lambda x: x[0], reverse = True)) + + # Sort the specific releases by version + for release_branch in gh_release_branches_dict: + gh_release_branches_dict[release_branch] = OrderedDict(sorted(gh_release_branches_dict[release_branch].items(), key = lambda x: x[0], reverse = True)) + + return gh_release_branches_dict + +""" +Retrieves the properties of a given GitHub asset. + +Args: + ecal_version (semantic_version.Version): The version of eCAL. + gh_asset (github.Asset): The GitHub asset object. + +Returns: + dict: A dictionary containing the properties of the asset, including: + + { + 'filename' : 'actual filename', + 'download_link': 'browser download link', + 'type' : 'source / ecal_installer / python_binding', + 'properties' : SEE BELOW, + } + + Properties for "source": + {} + + Properties for "ecal_installer": + { + 'os': 'windows / macos / ubuntu', + 'os_version': Semver('0.0.0') (Only for Ubuntu specific installers), + 'cpu': 'amd64 / arm64' + } + + Properties for "python_binding": + { + 'os': 'manylinux / macos / windows / ubuntu', + 'os_version': Semver('0.0.0') (Only for Ubuntu specific bindings), + 'cpu': 'amd64 / arm64', + 'python_version': Semver('3.6.0') (example) + 'python_implementation': 'cp / pp etc.' (i.e. CPython or PyPy) + } +""" +def get_asset_properties(ecal_version, gh_asset): + asset_properties = { + 'filename' : '', + 'download_link': '', + 'type' : '', + 'properties' : {}, + } + + asset_properties['filename'] = gh_asset.name + asset_properties['download_link'] = gh_asset.browser_download_url + + # Source + if asset_properties['filename'].endswith('tar.gz'): + asset_properties['type'] = 'source' + + # eCAL Installer for Windows + elif asset_properties['filename'].endswith('.msi') or asset_properties['filename'].endswith('.exe'): + asset_properties['type'] = 'ecal_installer' + asset_properties['properties']['os'] = 'windows' + asset_properties['properties']['cpu'] = 'amd64' + + # eCAL installer for macOS + elif asset_properties['filename'].endswith('.dmg'): + asset_properties['type'] = 'ecal_installer' + asset_properties['properties']['os'] = 'macos' + asset_properties['properties']['cpu'] = 'amd64' + + # eCAL Installer for Linux + elif asset_properties['filename'].endswith('.deb'): + asset_properties['type'] = 'ecal_installer' + asset_properties['properties']['os'] = 'ubuntu' + asset_properties['properties']['os_version'] = semantic_version.Version('0.0.0') + asset_properties['properties']['cpu'] = 'amd64' + + if ecal_version <= semantic_version.Version("5.7.2"): + # Special case for old releases. They only had Ubuntu 20.04 releases that were just named "linux". + asset_properties['properties']['os_version'] = semantic_version.Version("20.4.0") + else: + for codename, version in ubuntu_codename_dict.items(): + if codename in asset_properties['filename']: + asset_properties['properties']['os_version'] = version + break + + if ecal_version <= semantic_version.Version("5.7.2"): + # Special case for old releases. They only had Ubuntu 20.04 releases that were just named "linux". + asset_properties['properties']['os_version'] = semantic_version.Version("20.4.0") + + # Python binding (whl) + elif asset_properties['filename'].endswith('.whl'): + asset_properties['type'] = 'python_binding' + + # Get Operating system + if 'manylinux' in asset_properties['filename']: + asset_properties['properties']['os'] = 'manylinux' + elif 'darwin' in asset_properties['filename'] or 'macos' in asset_properties['filename']: + asset_properties['properties']['os'] = 'macos' + elif "win64" in asset_properties['filename'] or "win_amd64" in asset_properties['filename']: + asset_properties['properties']['os'] = 'windows' + elif 'linux' in asset_properties['filename']: + # Old eCAL 5.x wheels were Ubuntu specific + asset_properties['properties']['os'] = 'ubuntu' + for codename, version in ubuntu_codename_dict.items(): + if codename in asset_properties['filename']: + asset_properties['properties']['os_version'] = version + break + else: + sys.stderr.write("Warning: Unable to determine OS of python binding: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + # Get Python CPU Architecture + filename_without_extension = os.path.splitext(asset_properties['filename'])[0] + if filename_without_extension.endswith('amd64') or filename_without_extension.endswith('x86_64') or filename_without_extension.endswith('win64'): + asset_properties['properties']['cpu'] = 'amd64' + elif filename_without_extension.endswith('arm64') or filename_without_extension.endswith('aarch64'): + asset_properties['properties']['cpu'] = 'arm64' + else: + sys.stderr.write("Warning: Unable to determine CPU Architecture of python binding: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + # Get Python version + python_version = semantic_version.Version("0.0.0") + python_implementation = '' + components = asset_properties['filename'][:-4].split('-') + # The python version is either index 2 or 3, depending on whether the optional build tag is used. + for index in range(2,4): + if re.match(r"[a-z]{2}[0-9]+", components[index]): + python_implementation = components[index][:2] + python_version_major_string = components[index][2] + python_verstion_minor_string = "0" + if len(components[index]) > 3: + python_verstion_minor_string = components[index][3:] + python_version = semantic_version.Version(python_version_major_string + "." + python_verstion_minor_string + ".0") + break + + if python_version == semantic_version.Version("0.0.0"): + sys.stderr.write("Warning: Unable to determine python version: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + if not python_implementation: + sys.stderr.write("Warning: Unable to determine python implementation: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + asset_properties['properties']['python_version'] = python_version + asset_properties['properties']['python_implementation'] = python_implementation + + # Python binding (.egg) + elif asset_properties['filename'].endswith('.egg'): + asset_properties['type'] = 'python_binding' + + # Get Operating system + if 'darwin' in asset_properties['filename'] or 'macos' in asset_properties['filename']: + asset_properties['properties']['os'] = 'macos' + elif "win64" in asset_properties['filename'] or "win_amd64" in asset_properties['filename']: + asset_properties['properties']['os'] = 'windows' + elif 'linux' in asset_properties['filename'] or 'bionic' in asset_properties['filename'] or 'focal' in asset_properties['filename']: + asset_properties['properties']['os'] = 'ubuntu' + if ecal_version <= semantic_version.Version("5.7.2"): + # Special case for old releases. They only had Ubuntu 20.04 releases that were just named "linux". + asset_properties['properties']['os_version'] = semantic_version.Version("20.4.0") + else: + for codename, version in ubuntu_codename_dict.items(): + if codename in asset_properties['filename']: + asset_properties['properties']['os_version'] = version + break + + if not asset_properties['properties'].get('os'): + sys.stderr.write("Warning: Unable to determine OS of python binding: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + # Get python version + python_version = semantic_version.Version("0.0.0") + python_match_result = re.findall(r"py[0-9]+\.[0-9]+", asset_properties['filename']) + if len(python_match_result) > 0: + python_version = semantic_version.Version(python_match_result[0][2:] + ".0") + + if python_version == semantic_version.Version("0.0.0"): + sys.stderr.write("Warning: Unable to determine python version: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + asset_properties['properties']['python_version'] = python_version + asset_properties['properties']['python_implementation'] = 'cp' # The eggs were all CPython + + # CPU Architecture was always amd64 back then + asset_properties['properties']['cpu'] = 'amd64' + + # Warning, as we have no idea what this file is for + else: + sys.stderr.write("Warning: Unknown asset type: \"" + asset_properties['filename'] + "\" (from eCAL " + str(ecal_version) + ")\n") + + return asset_properties + +def generate_release_index_page(releases_dict, list_of_supported_minor_versions, output_filename): + # Create the output directory if it does not exist + output_dir = os.path.dirname(output_filename) + if output_dir and not os.path.exists(output_dir): + os.makedirs(output_dir) + + # Load the Jinja2 template + template_loader = jinja2.FileSystemLoader(searchpath="resource/") + template_env = jinja2.Environment(loader=template_loader) + template_file = "release_page_index.rst.jinja" + template = template_env.get_template(template_file) + + # Render the template with the context + context = { + 'releases_dict': releases_dict, + 'list_of_supported_minor_versions': list_of_supported_minor_versions, + 'group_asset_list_by_os_and_arch': group_asset_list_by_os_and_arch, + 'get_rst_release_page_label': get_rst_release_page_label, + } + output = template.render(context) + + # Save the rendered template to a file + with open(output_filename, "w") as f: + f.write(output) + +def generate_release_page(gh_release, + ecal_version, + asset_list, + minor_is_supported, + latest_version_of_minor, + output_dir): + ecal_version_string = str(ecal_version).replace('.', '_').replace('-', '_').replace('+', '_') + output_filename = "ecal_" + ecal_version_string + ".rst" + changelog_file = "changelog_ecal_" + ecal_version_string + ".txt" + + # Create the output directory if it does not exist + if output_dir and not os.path.exists(output_dir): + os.makedirs(output_dir) + + # Save the changelog to a file + changelog = gh_release.body + changelog = changelog.replace('\r\n', '\n') + with open(os.path.join(output_dir, changelog_file), "w") as f: + f.write(changelog) + + # Load the Jinja2 template + template_loader = jinja2.FileSystemLoader(searchpath="resource/") + template_env = jinja2.Environment(loader=template_loader) + template_file = "release_page.rst.jinja" + template = template_env.get_template(template_file) + + # Render the template with the context + context = { + 'gh_release': gh_release, + 'ecal_version': ecal_version, + 'asset_list': asset_list, + 'changelog_file_path': changelog_file, + 'minor_is_supported': minor_is_supported, + 'latest_version_of_minor': latest_version_of_minor, + 'ubuntu_default_python_version_dict': ubuntu_default_python_version_dict, + 'group_asset_list_by_os_and_arch': group_asset_list_by_os_and_arch, + 'get_rst_release_page_label': get_rst_release_page_label, + } + output = template.render(context) + + # Save the rendered template to a file + path = os.path.join(output_dir, output_filename) + with open(path, "w") as f: + f.write(output) + +""" +Groups a list of assets by their OS, OS version, and CPU architecture. +Args: + asset_list (list): A list of asset properties dictionaries. +Returns: + dict: A dictionary where the keys are tuples of (os, os_version, cpu) and + the values are lists of asset properties dictionaries. +""" +def group_asset_list_by_os_and_arch(asset_list): + os_arch_dict = OrderedDict() + + for asset_properties in asset_list: + os = asset_properties['properties'].get('os', 'unknown') + os_version = asset_properties['properties'].get('os_version', semantic_version.Version('0.0.0')) + cpu = asset_properties['properties'].get('cpu', 'unknown') + + key = (os, os_version, cpu) + if key not in os_arch_dict: + os_arch_dict[key] = [] + os_arch_dict[key].append(asset_properties) + + return os_arch_dict + +def get_rst_release_page_label(ecal_version): + return "ecal_release_page_" + str(ecal_version).replace('.', '_').replace('-', '_').replace('+', '_') + +def generate_release_documentation(gh_api_key, index_filepath, release_dir_path): + gh = github.Github(gh_api_key) + gh_repo = gh.get_repo("eclipse-ecal/ecal") + releases_dict = get_releases_dict(gh_repo) + + list_of_supported_minor_versions = list(releases_dict.keys())[:2] + + generate_release_index_page(releases_dict, + list_of_supported_minor_versions, + index_filepath) + + for minor_version in releases_dict: + + # Get the latest eCAL Version of this release branch + latest_release_for_this_minor = list(releases_dict[minor_version].keys())[0] + this_minor_is_supported = minor_version in list_of_supported_minor_versions + + for ecal_version in releases_dict[minor_version]: + + # Check the support status of this release + + gh_release = releases_dict[minor_version][ecal_version] + gh_asset_list = gh_release.get_assets() + + asset_list = [] + + for gh_asset in gh_asset_list: + asset_properties = get_asset_properties(ecal_version, gh_asset) + asset_list.append(asset_properties) + + # Sort the asset list by: + # 1. OS (windows > manylinux > ubuntu > macos) + # 2. OS version (descending) + # 3. CPU (amd64 > arm64) + # 4. Python version (descending) + + asset_list.sort(key = lambda x: x['properties'].get('python_version', semantic_version.Version("0.0.0")), reverse = True) + asset_list.sort(key = lambda x: x['properties'].get('os_version', semantic_version.Version("0.0.0")), reverse = True) + asset_list.sort(key = lambda x: x['properties'].get('cpu', 'unknown')) + asset_list.sort(key = lambda x: ['windows', 'manylinux', 'ubuntu', 'macos'].index(x['properties'].get('os', 'unknown')) if x['properties'].get('os', 'unknown') in ['windows', 'manylinux', 'ubuntu', 'macos'] else float('inf')) + + generate_release_page(gh_release, + ecal_version, + asset_list, + this_minor_is_supported, + latest_release_for_this_minor, + release_dir_path) + +if __name__=="__main__": + gh_api_key = os.getenv("ECAL_GH_API_KEY") + if gh_api_key: + generate_release_documentation(gh_api_key, "index.rst", "release") + else: + sys.stderr.write("ERROR: Environment variable ECAL_GH_API_KEY not set. Without an API key, GitHub will not provide enough API calls to generate the download tables.\n") + exit(1) + + + + + + + diff --git a/doc/release_page/resource/release_page.rst.jinja b/doc/release_page/resource/release_page.rst.jinja new file mode 100644 index 0000000000..4411a39b01 --- /dev/null +++ b/doc/release_page/resource/release_page.rst.jinja @@ -0,0 +1,206 @@ +{% set ecal_version_string = ecal_version | string -%} + +{# Makro for properly naming the OS, possibly with icon. e.g. "|fa-windows| Windows" (-> capitalized) or |fa-ubuntu| Ubuntu 24.04 (-> with Version number) -#} +{% macro get_os_string(asset, with_icon) -%} + {% if asset['properties']['os'] == 'windows' -%} + {% set os_string = (with_icon and '|fa-windows| ' or '') ~ 'Windows' -%} + {% elif asset['properties']['os'] == 'macos' -%} + {% set os_string = (with_icon and '|fa-apple| ' or '') ~ 'macOS' -%} + {% elif asset['properties']['os'] == 'ubuntu' -%} + {% set os_version_padded = asset['properties']['os_version'].major ~ '.' ~ '%02d' | format(asset['properties']['os_version'].minor) -%} + {% set os_string = (with_icon and '|fa-Ubuntu| ' or '') ~ 'Ubuntu ' ~ os_version_padded -%} + {% elif asset['properties']['os'] == 'manylinux' -%} + {% set os_string = (with_icon and '|fa-linux| ' or '') ~ 'Linux (All)' -%} + {% elif asset['properties']['os'] == '' -%} + {% set os_string = 'Unknown' -%} + {% else -%} + {% set os_string = asset['properties']['os'].capitalize() -%} + {% endif -%} + {{ os_string -}} +{% endmacro -%} + +{# Makro for naming the CPU Architecture. Mainly to make amd64 to x64, so the user can more easily distinguish it from arm64 #} +{% macro get_cpu_string(asset) -%} + {% if asset['properties']['cpu'] == 'amd64' -%} + {% set cpu_string = 'x64' -%} + {% elif asset['properties']['cpu'] == 'arm64' -%} + {% set cpu_string = 'ARM64' -%} + {% else -%} + {% set cpu_string = asset['properties']['cpu'] -%} + {% endif -%} + {{ cpu_string -}} +{% endmacro -%} +:orphan: + +.. include:: /../include.txt + +.. _{{ get_rst_release_page_label(ecal_version) }}: + +=============== +eCAL {{ ecal_version_string }} +=============== + +{% if not minor_is_supported %} +.. warning:: + + eCAL {{ ecal_version.major }}.{{ ecal_version.minor }} is not supported anymore. Please consider upgrading to a newer version. +{% endif %} + +- Release Date: {{ gh_release.published_at.strftime('%Y-%m-%d') }} +- GitHub Release Page: {{ gh_release.html_url }} + +Changelog +========= + +.. literalinclude:: {{ changelog_file_path }} + :language: text + +Downloads +========= + +{% if ecal_version < latest_version_of_minor %} +.. note:: + + A more recent version of eCAL {{ ecal_version.major }}.{{ ecal_version.minor }} is available: :ref:`eCAL {{ latest_version_of_minor }} <{{ get_rst_release_page_label(latest_version_of_minor) }}>`. +{% endif %} + +{# Get the ecal_installers from the list and remove them from the main list. -#} +{% set ecal_installer_list = asset_list | selectattr('type', 'equalto', 'ecal_installer') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'ecal_installer') | list -%} + +{% if ecal_installer_list %} +eCAL Installer +-------------- + +.. list-table:: + :widths: 2 2 6 + :header-rows: 1 + + * - OS + + - Architecture + + - Files + + {% for asset in ecal_installer_list -%} + + * - {{ get_os_string(asset, true) }} + + - {{ get_cpu_string(asset) }} + + - `{{ asset['filename'] }} <{{ asset['download_link'] }}>`__ + + {% endfor -%} + +{% endif -%} + +{# Get the python bindings from the list -#} +{% set python_binding_list = asset_list | selectattr('type', 'equalto', 'python_binding') | selectattr('properties.python_implementation', 'equalto', 'cp') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'python_binding') | list -%} + +{% if python_binding_list %} +|fa-python| Python Binding +-------------------------- + +.. list-table:: + :widths: 2 2 6 + :header-rows: 1 + + * - OS + + - Architecture + + - Files + + {% set python_binding_grouped_dict = group_asset_list_by_os_and_arch(python_binding_list) -%} + + {% for key, value in python_binding_grouped_dict.items() -%} + {% if value[0]['properties']['os'] == 'ubuntu' -%} + {% set default_python_version = ubuntu_default_python_version_dict[value[0]['properties']['os_version']] -%} + {% endif %} + * - {{ get_os_string(value[0], true) }} + + - {{ get_cpu_string(value[0]) }} + + - {% for asset in value -%} + `Python {{ asset['properties']['python_version'].major }}.{{ asset['properties']['python_version'].minor }} (.{{ asset['filename'].split('.')[-1] }}) <{{ asset['download_link'] }}>`__ {% if asset['properties']['python_version'] == default_python_version %} (Default){% endif %} + + {% endfor -%} + + {% endfor -%} + +{% endif -%} + +{# Get the PyPy bindings from the list -#} +{% set pypy_binding_list = asset_list | selectattr('type', 'equalto', 'python_binding') | selectattr('properties.python_implementation', 'equalto', 'pp') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'python_binding') | list -%} + +{% if pypy_binding_list %} +|fa-python| PyPy Binding +------------------------ + +*PyPy bindings are not compatibly with the regular Python implementation.* + +.. list-table:: + :widths: 2 2 6 + :header-rows: 1 + + * - OS + + - Architecture + + - Files + + {% set pypy_binding_grouped_dict = group_asset_list_by_os_and_arch(pypy_binding_list) -%} + + {% for key, value in pypy_binding_grouped_dict.items() %} + * - {{ get_os_string(value[0], true) }} + + - {{ get_cpu_string(value[0]) }} + + - {% for asset in value -%} + `PyPy {{ asset['properties']['python_version'].major }}.{{ asset['properties']['python_version'].minor }} (.{{ asset['filename'].split('.')[-1] }}) <{{ asset['download_link'] }}>`__ + + {% endfor -%} + + {% endfor -%} + +{% endif -%} + +{# Get the source files from the list -#} +{% set source_file_list = asset_list | selectattr('type', 'equalto', 'source') | list -%} +{% set asset_list = asset_list | rejectattr('type', 'equalto', 'source') | list -%} + +{% if source_file_list %} +|fa-code| Source +---------------- + +.. list-table:: + :widths: 1 + + {% for asset in source_file_list -%} + + * - `{{ asset['filename'] }} <{{ asset['download_link'] }}>`__ + + {% endfor -%} + +{% endif %} + +{# Get the other files from the list -#} +{% if asset_list %} +Other Downloads +--------------- + +.. list-table:: + :widths: 1 + :header-rows: 1 + + * - Files + + {% for asset in asset_list -%} + + * - `{{ asset['filename'] }} <{{ asset['download_link'] }}>`__ + + {% endfor -%} + +{% endif -%} \ No newline at end of file diff --git a/doc/release_page/resource/release_page_index.rst.jinja b/doc/release_page/resource/release_page_index.rst.jinja new file mode 100644 index 0000000000..30f6c6d4bc --- /dev/null +++ b/doc/release_page/resource/release_page_index.rst.jinja @@ -0,0 +1,49 @@ +.. include:: /../include.txt + +.. _all_releases: + +============= +eCAL Releases +============= + +Here you can find a list of all eCAL Versions ever released on GitHub. + +{% for minor_version, releases_dict in releases_dict.items() %} +eCAL {{ minor_version.major }}.{{ minor_version.minor }} +=========== + +{% if minor_version not in list_of_supported_minor_versions -%} + +*eCAL {{ minor_version.major }}.{{ minor_version.minor }} has reached its end of life.* + +{% endif -%} + +.. list-table:: + :widths: 3 3 4 + :header-rows: 1 + + * - Release + + - Release Date + + - Support Status + +{% for ecal_version, gh_release in releases_dict.items() -%} +{% set is_latest_release_in_this_minor = (ecal_version == releases_dict.keys()|list|first) %} + * - :ref:`eCAL {{ gh_release.tag_name }} <{{ get_rst_release_page_label(ecal_version) }}>` + + - {{ gh_release.published_at.strftime("%Y-%m-%d") }} + + - {% if (minor_version in list_of_supported_minor_versions) and is_latest_release_in_this_minor -%} + Supported + {% else -%} + EOL + {% endif -%} +{% endfor -%} + +{% endfor %} + +.. toctree:: + :hidden: + + eCAL Documentation \ No newline at end of file diff --git a/doc/requirements.txt b/doc/requirements.txt index 0b293dd97a..424039e7fa 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,16 +1,12 @@ wheel -sphinx-book-theme==0.3.3 -sphinx-tabs==3.3.1 +sphinx<7.3 +sphinx-book-theme==1.1.2 +sphinx-tabs==3.4.5 PyGithub autodoc -empy<=3.3.4 +empy==3.3.4 # The empy_helpers are incompatible with Empy 4.0. Also see this issue: https://github.com/ros2/rosidl/issues/779 semantic-version exhale Jinja2 -sphinxcontrib-youtube<=1.2 sphinxcontrib-apidoc -sphinxcontrib-applehelp<=1.0.7 # 2024-01-15: Newer packages needs Sphinx 5 or up, but our old sphinx-book-theme 0.3.3 requires Sphinx 4 -sphinxcontrib-devhelp<=1.0.5 # 2024-01-15: Newer packages need Sphinx 5 or up, but our old sphinx-book-theme 0.3.3 requires Sphinx 4 -sphinxcontrib-htmlhelp<=2.0.4 # 2024-01-15: Newer packages (probably) need Sphinx 5 or up, but our old sphinx-book-theme 0.3.3 requires Sphinx 4 -sphinxcontrib-qthelp<=1.0.6 # 2024-01-15: Newer packages (probably) need Sphinx 5 or up, but our old sphinx-book-theme 0.3.3 requires Sphinx 4 -sphinxcontrib-serializinghtml<=1.1.9 # 2024-01-15: Newer packages (probably) need Sphinx 5 or up, but our old sphinx-book-theme 0.3.3 requires Sphinx 4 \ No newline at end of file +sphinxcontrib-youtube diff --git a/doc/rst/_css_helpers/ecal-for-book-0.4.css b/doc/rst/_css_helpers/ecal-for-book-0.4.css deleted file mode 100644 index adabd0cfa4..0000000000 --- a/doc/rst/_css_helpers/ecal-for-book-0.4.css +++ /dev/null @@ -1,4 +0,0 @@ -html[data-theme=dark], -html[data-theme=light] { - --pst-color-primary: rgb(255, 165, 0); -} \ No newline at end of file diff --git a/doc/rst/_css_helpers/pydata-sphinx-theme-0.15.2-orig.css b/doc/rst/_css_helpers/pydata-sphinx-theme-0.15.2-orig.css new file mode 100644 index 0000000000..30edf86ce1 --- /dev/null +++ b/doc/rst/_css_helpers/pydata-sphinx-theme-0.15.2-orig.css @@ -0,0 +1,3623 @@ +html { + --pst-header-height: 4rem; + --pst-header-article-height: calc(var(--pst-header-height)*2/3); + --pst-sidebar-secondary: 17rem; + --pst-font-size-base: 1rem; + --pst-font-size-h1: 2.5rem; + --pst-font-size-h2: 2rem; + --pst-font-size-h3: 1.75rem; + --pst-font-size-h4: 1.5rem; + --pst-font-size-h5: 1.25rem; + --pst-font-size-h6: 1.1rem; + --pst-font-size-milli: 0.9rem; + --pst-sidebar-font-size: 0.9rem; + --pst-sidebar-font-size-mobile: 1.1rem; + --pst-sidebar-header-font-size: 1.2rem; + --pst-sidebar-header-font-weight: 600; + --pst-admonition-font-weight-heading: 600; + --pst-font-weight-caption: 300; + --pst-font-weight-heading: 400; + --pst-font-family-base-system: -apple-system, BlinkMacSystemFont, Segoe UI, "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol; + --pst-font-family-monospace-system: "SFMono-Regular", Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace; + --pst-font-family-base: var(--pst-font-family-base-system); + --pst-font-family-heading: var(--pst-font-family-base-system); + --pst-font-family-monospace: var(--pst-font-family-monospace-system); + --pst-font-size-icon: 1.5rem; + --pst-icon-check-circle: ""; + --pst-icon-info-circle: ""; + --pst-icon-exclamation-triangle: ""; + --pst-icon-exclamation-circle: ""; + --pst-icon-times-circle: ""; + --pst-icon-lightbulb: ""; + --pst-icon-download: ""; + --pst-icon-angle-left: ""; + --pst-icon-angle-right: ""; + --pst-icon-external-link: ""; + --pst-icon-search-minus: ""; + --pst-icon-github: ""; + --pst-icon-gitlab: ""; + --pst-icon-share: ""; + --pst-icon-bell: ""; + --pst-icon-pencil: ""; + --pst-breadcrumb-divider: ""; + --pst-icon-admonition-default: var(--pst-icon-bell); + --pst-icon-admonition-note: var(--pst-icon-info-circle); + --pst-icon-admonition-attention: var(--pst-icon-exclamation-circle); + --pst-icon-admonition-caution: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-warning: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-danger: var(--pst-icon-exclamation-triangle); + --pst-icon-admonition-error: var(--pst-icon-times-circle); + --pst-icon-admonition-hint: var(--pst-icon-lightbulb); + --pst-icon-admonition-tip: var(--pst-icon-lightbulb); + --pst-icon-admonition-important: var(--pst-icon-exclamation-circle); + --pst-icon-admonition-seealso: var(--pst-icon-share); + --pst-icon-admonition-todo: var(--pst-icon-pencil); + --pst-icon-versionmodified-default: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-added: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-changed: var(--pst-icon-exclamation-circle); + --pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-circle); + font-size: var(--pst-font-size-base); + scroll-padding-top: calc(var(--pst-header-height) + 1rem) +} + +body { + background-color: var(--pst-color-background); + color: var(--pst-color-text-base); + display: flex; + flex-direction: column; + font-family: var(--pst-font-family-base); + font-weight: 400; + line-height: 1.65; + min-height: 100vh +} + +body::-webkit-scrollbar-track { + background: var(--pst-color-background) +} + +p { + color: var(--pst-color-text-base); + font-size: 1em; + margin-bottom: 1.15rem +} + +p.rubric { + border-bottom: 1px solid var(--pst-color-border) +} + +p.centered { + text-align: center +} + +a { + word-wrap: break-word; + color: var(--pst-color-link); + text-decoration: underline; + text-decoration-thickness: max(1px, .0625rem); + text-underline-offset: .1578em +} + +a:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration-skip-ink: none; + text-decoration-thickness: max(3px, .1875rem, .12em) +} + +a:active, +a:visited { + color: var(--pst-color-link) +} + +a:visited:hover { + color: var(--pst-color-link-hover) +} + +a:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +a.headerlink { + color: var(--pst-color-secondary); + font-size: .8em; + margin-left: .2em; + opacity: .7; + padding: 0 4px; + text-decoration: none; + transition: all .2s ease-out; + user-select: none +} + +a.headerlink:hover { + opacity: 1 +} + +a.github:before, +a.gitlab:before { + color: var(--pst-color-text-muted); + font: var(--fa-font-brands); + margin-right: .25rem +} + +a.github:before { + content: var(--pst-icon-github) +} + +a.gitlab:before { + content: var(--pst-icon-gitlab) +} + +.heading-style, +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: var(--pst-font-family-heading); + font-weight: var(--pst-font-weight-heading); + line-height: 1.15; + margin: 2.75rem 0 1.05rem +} + +h1 { + font-size: var(--pst-font-size-h1); + margin-top: 0 +} + +h1, +h2 { + color: var(--pst-heading-color) +} + +h2 { + font-size: var(--pst-font-size-h2) +} + +h3 { + font-size: var(--pst-font-size-h3) +} + +h3, +h4 { + color: var(--pst-heading-color) +} + +h4 { + font-size: var(--pst-font-size-h4) +} + +h5 { + font-size: var(--pst-font-size-h5) +} + +h5, +h6 { + color: var(--pst-color-text-base) +} + +h6 { + font-size: var(--pst-font-size-h6) +} + +.text_small, +small { + font-size: var(--pst-font-size-milli) +} + +hr { + border: 0; + border-top: 1px solid var(--pst-color-border) +} + +code, +kbd, +pre, +samp { + font-family: var(--pst-font-family-monospace) +} + +kbd { + background-color: var(--pst-color-on-background); + color: var(--pst-color-text-muted) +} + +kbd:not(.compound) { + border: 1px solid var(--pst-color-border); + box-shadow: 1px 1px 1px var(--pst-color-shadow); + margin: 0 .1rem; + padding: .1rem .4rem +} + +code { + color: var(--pst-color-inline-code) +} + +pre { + background-color: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + border-radius: .25rem; + color: var(--pst-color-text-base); + line-height: 1.2em; + margin: 1.5em 0; + padding: 1rem +} + +pre .linenos { + opacity: .8; + padding-right: 10px +} + +#pst-back-to-top { + background-color: var(--pst-color-secondary); + border: none; + color: var(--pst-color-secondary-text); + display: none; + left: 50vw; + position: fixed; + top: 90vh; + transform: translate(-50%); + z-index: 1080 +} + +.skip-link { + background-color: var(--pst-color-warning); + border-bottom: 1px solid var(--pst-color-border); + color: var(--pst-color-warning-text) !important; + left: 0; + padding: .5rem; + position: fixed; + right: 0; + text-align: center; + top: 0; + transform: translateY(-100%); + transition: transform .15s ease-in-out; + z-index: 1055 +} + +.skip-link:focus { + outline: 3px solid #14181e; + transform: translateY(0) +} + +.bd-container { + display: flex; + flex-grow: 1; + justify-content: center +} + +.bd-container .bd-container__inner { + display: flex +} + +.bd-page-width { + width: 100% +} + +@media(min-width:960px) { + .bd-page-width { + max-width: 88rem + } +} + +.bd-header-announcement, +.bd-header-version-warning { + align-items: center; + display: flex; + justify-content: center; + min-height: 3rem; + padding: .5rem 12.5%; + position: relative; + text-align: center; + width: 100% +} + +@media(max-width:959.98px) { + + .bd-header-announcement, + .bd-header-version-warning { + padding: .5rem 2% + } +} + +.bd-header-announcement p, +.bd-header-version-warning p { + font-weight: 700; + margin: 0 +} + +.bd-header-announcement:after, +.bd-header-version-warning:after { + content: ""; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; + z-index: -1 +} + +.bd-header-announcement:empty, +.bd-header-version-warning:empty { + display: none +} + +.bd-header-announcement a, +.bd-header-version-warning a { + color: var(--pst-color-inline-code-links) +} + +.bd-header-announcement:after { + background-color: var(--pst-color-secondary-bg) +} + +.bd-header-version-warning:after { + background-color: var(--pst-color-danger-bg) +} + +.bd-main { + display: flex; + flex-direction: column; + flex-grow: 1; + min-width: 0 +} + +.bd-main .bd-content { + display: flex; + height: 100%; + justify-content: center +} + +.bd-main .bd-content .bd-article-container { + display: flex; + flex-direction: column; + justify-content: start; + max-width: 60em; + overflow-x: auto; + padding: 1rem; + width: 100% +} + +@media(min-width:1200px) { + .bd-main .bd-content .bd-article-container .bd-article { + padding-left: 2rem; + padding-top: 1.5rem + } +} + +.bd-footer { + border-top: 1px solid var(--pst-color-border); + width: 100% +} + +.bd-footer .bd-footer__inner { + display: flex; + flex-grow: 1; + margin: auto; + padding: 1rem +} + +.bd-footer .footer-items__center, +.bd-footer .footer-items__end, +.bd-footer .footer-items__start { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: .5rem; + justify-content: center +} + +.bd-footer .footer-items__center { + text-align: center +} + +.bd-footer .footer-items__end { + text-align: end +} + +.bd-footer .footer-item p { + margin-bottom: 0 +} + +.bd-footer-article { + margin-top: auto +} + +.bd-footer-article .footer-article-items { + display: flex; + flex-direction: column +} + +.bd-footer-content .footer-content-items { + display: flex; + flex-direction: column; + margin-top: auto +} + +.bd-header { + background: var(--pst-color-on-background) !important; + box-shadow: 0 .125rem .25rem 0 var(--pst-color-shadow); + justify-content: center; + max-width: 100vw; + padding: 0; + position: sticky; + top: 0; + width: 100%; + z-index: 1030 +} + +.bd-header .bd-header__inner { + align-items: center; + display: flex; + height: fit-content; + padding-left: 1rem; + padding-right: 1rem +} + +.bd-header .navbar-item { + align-items: center; + display: flex; + height: var(--pst-header-height); + max-height: var(--pst-header-height) +} + +.bd-header .navbar-header-items { + flex-shrink: 1 +} + +@media(min-width:960px) { + .bd-header .navbar-header-items { + display: flex; + flex-grow: 1; + padding: 0 0 0 .5rem + } +} + +.bd-header .navbar-header-items__center, +.bd-header .navbar-header-items__end, +.bd-header .navbar-header-items__start { + align-items: center; + display: flex; + flex-flow: wrap; + row-gap: 0 +} + +.bd-header .navbar-header-items__center, +.bd-header .navbar-header-items__end { + column-gap: 1rem +} + +.bd-header .navbar-header-items__start { + flex-shrink: 0; + gap: .5rem; + margin-right: auto +} + +.bd-header .navbar-header-items__end { + justify-content: end +} + +.bd-header .navbar-nav { + display: flex +} + +@media(min-width:960px) { + .bd-header .navbar-nav { + align-items: center + } +} + +.bd-header .navbar-nav li a.nav-link { + color: var(--pst-color-text-muted); + text-decoration: none +} + +.bd-header .navbar-nav li a.nav-link:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.bd-header .navbar-nav li a.nav-link:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.bd-header .navbar-nav>.current>.nav-link { + border-bottom: max(3px, .1875rem, .12em) solid var(--pst-color-primary); + color: var(--pst-color-primary); + font-weight: 600 +} + +.bd-header .navbar-nav .dropdown button { + border: none; + color: var(--pst-color-text-muted); + display: unset +} + +.bd-header .navbar-nav .dropdown button:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.bd-header .navbar-nav .dropdown button:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.bd-header .navbar-nav .dropdown .dropdown-menu { + background-color: var(--pst-color-on-background); + border: 1px solid var(--pst-color-border); + box-shadow: 0 0 .3rem .1rem var(--pst-color-shadow); + margin: .5rem 0; + min-width: 20rem; + padding: .5rem 0; + z-index: 1070 +} + +.bd-header .navbar-nav .dropdown .dropdown-menu .dropdown-item { + padding: .25rem 1.5rem +} + +.bd-header .navbar-nav .dropdown .dropdown-menu .dropdown-item:focus:not(:hover):not(:active) { + background-color: inherit +} + +.bd-header .navbar-nav .dropdown .dropdown-menu:not(.show) { + display: none +} + +@media(min-width:960px) { + .navbar-center-items .navbar-item { + display: inline-block + } +} + +.nav-link { + transition: none +} + +.nav-link:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.nav-link.nav-external:after { + content: var(--pst-icon-external-link); + font: var(--fa-font-solid); + font-size: .75em; + margin-left: .3em +} + +.bd-navbar-elements li.nav-item i { + font-size: .7rem; + padding-left: 2px; + vertical-align: middle +} + +.bd-header label.sidebar-toggle { + align-items: center; + color: var(--pst-color-muted); + cursor: pointer; + display: flex; + font-size: var(--pst-font-size-icon); + margin-bottom: 0; + padding-bottom: .25rem +} + +.bd-header label.primary-toggle { + margin-right: 1rem +} + +@media(min-width:960px) { + .bd-header label.primary-toggle { + display: none + } +} + +.bd-header label.secondary-toggle { + margin-left: 1rem +} + +@media(min-width:1200px) { + .bd-header label.secondary-toggle { + display: none + } +} + +.bd-header label:hover { + box-shadow: 0 max(3px, .1875rem, .12em) 0 var(--pst-color-link-hover); + color: var(--pst-color-link-hover) +} + +.bd-header label:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.bd-header .navbar-header-items { + display: none +} + +@media(min-width:960px) { + .bd-header .navbar-header-items { + display: inherit + } +} + +.navbar-persistent--mobile { + margin-left: auto +} + +@media(min-width:960px) { + .navbar-persistent--mobile { + display: none + } +} + +.navbar-persistent--container { + display: none +} + +@media(min-width:960px) { + .navbar-persistent--container { + display: flex + } +} + +.header-article__inner { + display: flex; + padding: 0 .5rem +} + +.header-article__inner .header-article-item { + height: var(--pst-header-article-height); + min-height: var(--pst-header-article-height) +} + +.header-article__inner .header-article-items__end, +.header-article__inner .header-article-items__start { + align-items: start; + display: flex; + gap: .5rem +} + +.header-article__inner .header-article-items__end { + margin-left: auto +} + +.bd-sidebar-primary { + background-color: var(--pst-color-background); + border-right: 1px solid var(--pst-color-border); + display: flex; + flex: 0 0 auto; + flex-direction: column; + font-size: var(--pst-sidebar-font-size-mobile); + gap: 1rem; + max-height: calc(100vh - var(--pst-header-height)); + overflow-y: auto; + padding: 2rem 1rem 1rem; + position: sticky; + top: var(--pst-header-height); + width: 25% +} + +@media(min-width:960px) { + .bd-sidebar-primary { + font-size: var(--pst-sidebar-font-size) + } +} + +.bd-sidebar-primary .nav-link { + font-size: var(--pst-sidebar-font-size-mobile) +} + +.bd-sidebar-primary.no-sidebar { + border-right: 0 +} + +@media(min-width:960px) { + .bd-sidebar-primary.hide-on-wide { + display: none + } +} + +.bd-sidebar-primary h1, +.bd-sidebar-primary h2, +.bd-sidebar-primary h3, +.bd-sidebar-primary h4 { + color: var(--pst-color-text-base) +} + +.bd-sidebar-primary .sidebar-primary-items__end .sidebar-primary-item, +.bd-sidebar-primary .sidebar-primary-items__start .sidebar-primary-item { + padding: .5rem 0 +} + +.bd-sidebar-primary .sidebar-header-items { + display: flex; + flex-direction: column +} + +.bd-sidebar-primary .sidebar-header-items .sidebar-header-items__title { + color: var(--pst-color-text-base); + font-size: var(--pst-sidebar-header-font-size); + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: .5rem +} + +.bd-sidebar-primary .sidebar-header-items .nav-item.dropdown button { + display: none +} + +.bd-sidebar-primary .sidebar-header-items .nav-item.dropdown .dropdown-menu { + background-color: inherit; + border: none; + display: flex; + flex-direction: column; + font-size: inherit; + margin: 0; + padding: 0 +} + +.bd-sidebar-primary .sidebar-header-items .sidebar-header-items__center { + display: flex; + flex-direction: column +} + +.bd-sidebar-primary .sidebar-header-items .sidebar-header-items__end { + align-items: center; + display: flex; + gap: .5rem +} + +@media(min-width:960px) { + .bd-sidebar-primary .sidebar-header-items { + display: none + } +} + +.bd-sidebar-primary .sidebar-primary-items__start { + border-top: 1px solid var(--pst-color-border) +} + +@media(min-width:960px) { + .bd-sidebar-primary .sidebar-primary-items__start { + border-top: none + } +} + +.bd-sidebar-primary .sidebar-primary-items__end { + margin-bottom: 1em; + margin-top: auto +} + +.bd-sidebar-primary .list-caption { + list-style: none; + padding-left: 0 +} + +.bd-sidebar-primary li { + position: relative +} + +.bd-sidebar-primary li.has-children>.reference { + padding-right: 30px +} + +.bd-sidebar-primary label.toctree-toggle { + align-items: center; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + position: absolute; + right: 0; + top: 0; + width: 30px +} + +.bd-sidebar-primary label.toctree-toggle:hover { + background: var(--pst-color-surface) +} + +.bd-sidebar-primary label.toctree-toggle i { + display: inline-block; + font-size: .75rem; + text-align: center +} + +.bd-sidebar-primary label.toctree-toggle i:hover { + color: var(--pst-color-primary) +} + +.bd-sidebar-primary .label-parts { + height: 100%; + width: 100% +} + +.bd-sidebar-primary .label-parts:hover { + background: none +} + +.bd-sidebar-primary .label-parts i { + position: absolute; + right: 0; + top: .3em; + width: 30px +} + +nav.bd-links { + margin-right: -1rem +} + +@media(min-width:960px) { + nav.bd-links { + display: block + } +} + +nav.bd-links ul { + list-style: none +} + +nav.bd-links ul ul { + padding: 0 0 0 1rem +} + +nav.bd-links li>a { + box-shadow: none; + color: var(--pst-color-text-muted); + display: block; + padding: .25rem .65rem; + text-decoration: none +} + +nav.bd-links li>a:hover { + text-decoration-skip: none; + background-color: transparent; + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(3px, .1875rem, .12em) +} + +nav.bd-links li>a:active, +nav.bd-links li>a:hover { + color: var(--pst-color-link-hover) +} + +nav.bd-links li>a.reference.external:after { + content: var(--pst-icon-external-link); + font: var(--fa-font-solid); + font-size: .75em; + margin-left: .3em +} + +nav.bd-links .current>a { + background-color: transparent; + box-shadow: inset max(3px, .1875rem, .12em) 0 0 var(--pst-color-primary); + color: var(--pst-color-primary); + font-weight: 600 +} + +nav.bd-links p.bd-links__title { + font-size: var(--pst-sidebar-header-font-size) +} + +nav.bd-links p.bd-links__title, +nav.bd-links p.caption { + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: .5rem +} + +nav.bd-links p.caption { + color: var(--pst-color-text-base); + font-size: var(--pst-sidebar-font-size-mobile); + margin-top: 1.25rem; + position: relative +} + +nav.bd-links p.caption:first-child { + margin-top: 0 +} + +@media(min-width:960px) { + nav.bd-links p.caption { + font-size: var(--pst-sidebar-font-size) + } +} + +.bd-sidebar-secondary { + background-color: var(--pst-color-background); + display: flex; + flex-direction: column; + flex-shrink: 0; + font-size: var(--pst-sidebar-font-size-mobile); + max-height: calc(100vh - var(--pst-header-height)); + order: 2; + overflow-y: auto; + padding: 2rem 1rem 1rem; + position: sticky; + top: var(--pst-header-height); + width: var(--pst-sidebar-secondary) +} + +@media(min-width:1200px) { + .bd-sidebar-secondary { + font-size: var(--pst-sidebar-font-size) + } +} + +.sidebar-secondary-item { + padding: .5rem +} + +@media(min-width:1200px) { + .sidebar-secondary-item { + border-left: 1px solid var(--pst-color-border); + padding-left: 1rem + } +} + +.sidebar-secondary-item i { + padding-right: .5rem +} + +input.sidebar-toggle { + display: none +} + +label.overlay { + background-color: #000; + height: 0; + left: 0; + opacity: .5; + position: fixed; + top: 0; + transition: opacity .2s ease-out; + width: 0; + z-index: 1050 +} + +input#__primary:checked+label.overlay.overlay-primary, +input#__secondary:checked+label.overlay.overlay-secondary { + height: 100vh; + width: 100vw +} + +input#__primary:checked~.bd-container .bd-sidebar-primary { + margin-left: 0; + visibility: visible +} + +input#__secondary:checked~.bd-container .bd-sidebar-secondary { + margin-right: 0; + visibility: visible +} + +@media(min-width:960px) { + label.sidebar-toggle.primary-toggle { + display: none + } + + input#__primary:checked+label.overlay.overlay-primary { + height: 0; + width: 0 + } + + .bd-sidebar-primary { + margin-left: 0; + visibility: visible + } +} + +@media(max-width:959.98px) { + .bd-sidebar-primary { + flex-grow: .75; + height: 100vh; + left: 0; + margin-left: -75%; + max-height: 100vh; + max-width: 350px; + position: fixed; + top: 0; + transition: visibility .2s ease-out, margin .2s ease-out; + visibility: hidden; + width: 75%; + z-index: 1055 + } +} + +@media(max-width:1199.98px) { + .bd-sidebar-secondary { + flex-grow: .75; + height: 100vh; + margin-right: -75%; + max-height: 100vh; + max-width: 350px; + position: fixed; + right: 0; + top: 0; + transition: visibility .2s ease-out, margin .2s ease-out; + visibility: hidden; + width: 75%; + z-index: 1055 + } +} + +ul.bd-breadcrumbs { + display: flex; + flex-wrap: wrap; + font-size: .8rem; + list-style: none; + padding-left: 0 +} + +ul.bd-breadcrumbs li.breadcrumb-item { + align-items: center; + display: flex; + font-weight: 700 +} + +ul.bd-breadcrumbs li.breadcrumb-item a { + color: var(--pst-color-text-muted); + text-decoration: none +} + +ul.bd-breadcrumbs li.breadcrumb-item a:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +ul.bd-breadcrumbs li.breadcrumb-item a:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +ul.bd-breadcrumbs li.breadcrumb-item:not(.breadcrumb-home):before { + color: var(--pst-color-text-muted); + content: var(--pst-breadcrumb-divider); + font: var(--fa-font-solid); + font-size: .8rem; + padding: 0 .5rem +} + +.navbar-icon-links { + column-gap: 1rem; + display: flex; + flex-direction: row; + flex-wrap: wrap +} + +.navbar-icon-links li.nav-item a.nav-link { + padding-left: 0; + padding-right: 0 +} + +.navbar-icon-links li.nav-item a.nav-link:hover { + box-shadow: 0 max(3px, .1875rem, .12em) 0 var(--pst-color-link-hover); + color: var(--pst-color-link-hover) +} + +.navbar-icon-links a span { + align-items: center; + display: flex +} + +.navbar-icon-links i.fa-brands, +.navbar-icon-links i.fa-regular, +.navbar-icon-links i.fa-solid { + font-size: var(--pst-font-size-icon); + font-style: normal; + vertical-align: middle +} + +.navbar-icon-links i.fa-square-twitter:before { + color: #55acee +} + +.navbar-icon-links i.fa-square-gitlab:before { + color: #548 +} + +.navbar-icon-links i.fa-bitbucket:before { + color: #0052cc +} + +.navbar-icon-links img.icon-link-image { + border-radius: .2rem; + height: 1.5em +} + +.navbar-brand { + align-items: center; + display: flex; + flex-shrink: 0; + gap: .5rem; + height: var(--pst-header-height); + margin: 0; + max-height: var(--pst-header-height); + padding: .5rem 0; + position: relative; + width: auto +} + +.navbar-brand p { + margin-bottom: 0 +} + +.navbar-brand img { + height: 100%; + max-width: 100%; + width: auto +} + +.navbar-brand a { + text-decoration: none +} + +.navbar-brand:hover:hover, +.navbar-brand:visited:hover:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.navbar-nav ul { + display: block; + list-style: none +} + +.navbar-nav ul ul { + padding: 0 0 0 1rem +} + +.navbar-nav li { + display: flex; + flex-direction: column +} + +.navbar-nav li a { + align-items: center; + color: var(--pst-color-text-muted); + display: flex; + height: 100%; + padding-bottom: .25rem; + padding-top: .25rem; + text-decoration: none +} + +.navbar-nav li a:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.navbar-nav li a:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.navbar-nav .toctree-checkbox { + display: none; + position: absolute +} + +.navbar-nav .toctree-checkbox~ul { + display: none +} + +.navbar-nav .toctree-checkbox~label .fa-chevron-down { + transform: rotate(0deg) +} + +.navbar-nav .toctree-checkbox:checked~ul { + display: block +} + +.navbar-nav .toctree-checkbox:checked~label .fa-chevron-down { + transform: rotate(180deg) +} + +.page-toc .section-nav { + border-bottom: none; + padding-left: 0 +} + +.page-toc .section-nav ul { + padding-left: 1rem +} + +.page-toc .nav-link { + font-size: var(--pst-sidebar-font-size-mobile) +} + +@media(min-width:1200px) { + .page-toc .nav-link { + font-size: var(--pst-sidebar-font-size) + } +} + +.page-toc .onthispage { + color: var(--pst-color-text-base); + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: .5rem +} + +.prev-next-area { + width: 100% +} + +.prev-next-area p { + line-height: 1.3em; + margin: 0 .3em +} + +.prev-next-area i { + font-size: 1.2em +} + +.prev-next-area a { + align-items: center; + border: none; + color: var(--pst-color-text-muted); + display: flex; + max-width: 45%; + overflow-x: hidden; + padding: 10px; + text-decoration: none +} + +.prev-next-area a p.prev-next-title { + word-wrap: break-word; + color: var(--pst-color-link); + font-size: 1.1em; + font-weight: var(--pst-admonition-font-weight-heading); + text-decoration: underline; + text-decoration-thickness: max(1px, .0625rem); + text-underline-offset: .1578em +} + +.prev-next-area a p.prev-next-title:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration-skip-ink: none; + text-decoration-thickness: max(3px, .1875rem, .12em) +} + +.prev-next-area a p.prev-next-title:active, +.prev-next-area a p.prev-next-title:visited { + color: var(--pst-color-link) +} + +.prev-next-area a p.prev-next-title:visited:hover { + color: var(--pst-color-link-hover) +} + +.prev-next-area a p.prev-next-title:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.prev-next-area a:hover p.prev-next-title:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.prev-next-area a:visited p.prev-next-title { + color: var(--pst-color-link) +} + +.prev-next-area a:visited p.prev-next-title:hover { + color: var(--pst-color-link-hover) +} + +.prev-next-area a .prev-next-info { + flex-direction: column; + margin: 0 .5em +} + +.prev-next-area a .prev-next-info .prev-next-subtitle { + text-transform: capitalize +} + +.prev-next-area a.left-prev { + float: left +} + +.prev-next-area a.right-next { + float: right +} + +.prev-next-area a.right-next div.prev-next-info { + text-align: right +} + +.bd-search { + border: 1px solid var(--pst-color-border); + border-radius: .25rem; + color: var(--pst-color-text-base); + gap: .5rem; + padding-left: .5rem; + position: relative +} + +.bd-search, +.bd-search:active { + background-color: var(--pst-color-background) +} + +.bd-search:active { + color: var(--pst-color-text-muted) +} + +.bd-search .icon { + color: var(--pst-color-border); + left: 25px; + position: absolute +} + +.bd-search .fa-solid.fa-magnifying-glass { + color: var(--pst-color-text-muted); + left: calc(1.25rem - .35em); + position: absolute +} + +.bd-search input::placeholder { + color: var(--pst-color-text-muted) +} + +.bd-search input::-webkit-search-cancel-button, +.bd-search input::-webkit-search-decoration { + -webkit-appearance: none; + appearance: none +} + +.bd-search .search-button__kbd-shortcut { + color: var(--pst-color-border); + display: flex; + position: absolute; + right: .5rem +} + +.form-control { + background-color: var(--pst-color-background); + color: var(--pst-color-text-base) +} + +.form-control:focus, +.form-control:focus-visible { + background-color: var(--pst-color-background); + border: none; + box-shadow: none; + color: var(--pst-color-text-muted); + outline: 3px solid var(--pst-color-accent) +} + +.search-button { + align-content: center; + align-items: center; + border-radius: 0; + color: var(--pst-color-text-muted); + display: flex +} + +.search-button:hover { + box-shadow: 0 max(3px, .1875rem, .12em) 0 var(--pst-color-link-hover); + color: var(--pst-color-link-hover) +} + +.search-button:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.search-button i { + font-size: 1.3rem +} + +.search-button__overlay, +.search-button__search-container { + display: none +} + +.search-button__wrapper.show .search-button__search-container { + display: flex; + left: 50%; + margin-top: .5rem; + max-width: 800px; + position: fixed; + right: 1rem; + top: 30%; + transform: translate(-50%, -50%); + width: 90%; + z-index: 1055 +} + +.search-button__wrapper.show .search-button__overlay { + background-color: #000; + display: flex; + height: 100%; + left: 0; + opacity: .5; + position: fixed; + top: 0; + width: 100%; + z-index: 1050 +} + +.search-button__wrapper.show form.bd-search { + flex-grow: 1; + padding-bottom: 0; + padding-top: 0 +} + +.search-button__wrapper.show input, +.search-button__wrapper.show svg { + font-size: var(--pst-font-size-icon) +} + +.search-button-field { + align-items: center; + background-color: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + border-radius: 1.5em; + color: var(--pst-color-text-muted); + display: inline-flex; + padding: .5em +} + +.search-button-field:hover { + border: 2px solid var(--pst-color-link-hover) +} + +.search-button-field:focus-visible { + border: 2px solid var(--pst-color-accent) +} + +.search-button-field .search-button__default-text { + font-size: var(--bs-nav-link-font-size); + font-weight: var(--bs-nav-link-font-weight); + margin-left: .5em; + margin-right: .5em +} + +.search-button-field .kbd-shortcut__modifier { + font-size: .75em +} + +.search-button-field>* { + align-items: center +} + +.search-button-field>:not(svg) { + display: none +} + +@media(min-width:960px) { + .search-button-field>:not(svg) { + display: flex + } +} + +div#searchbox p.highlight-link { + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important; + margin: 1rem 0; + width: fit-content +} + +@media(min-width:1200px) { + div#searchbox p.highlight-link { + margin-left: 2rem + } +} + +div#searchbox p.highlight-link a { + background-color: var(--pst-color-primary); + border-radius: .25rem; + color: var(--pst-color-primary-text); + font-size: 1.25rem; + padding: .75rem; + text-decoration: none; + transition: box-shadow .25s ease-out +} + +div#searchbox p.highlight-link a:hover { + box-shadow: inset 0 0 50px 50px rgba(0, 0, 0, .25) +} + +div#searchbox p.highlight-link a:before { + color: unset; + content: var(--pst-icon-search-minus); + font: var(--fa-font-solid); + margin-right: .5rem +} + +.theme-switch-button { + border-radius: 0; + color: var(--pst-color-text-muted); + margin: 0 -.5rem; + padding: 0 +} + +.theme-switch-button:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +.theme-switch-button span { + display: none; + padding: .5em +} + +.theme-switch-button span:hover { + box-shadow: 0 max(3px, .1875rem, .12em) 0 var(--pst-color-link-hover); + color: var(--pst-color-link-hover) +} + +.theme-switch-button span:active { + color: var(--pst-color-link-hover); + text-decoration: none +} + +html[data-mode=auto] .theme-switch-button span[data-mode=auto], +html[data-mode=dark] .theme-switch-button span[data-mode=dark], +html[data-mode=light] .theme-switch-button span[data-mode=light] { + display: flex +} + +button.btn.version-switcher__button { + border-color: var(--pst-color-border); + color: var(--pst-color-text-base); + margin-bottom: 1em +} + +@media(min-width:960px) { + button.btn.version-switcher__button { + margin-bottom: unset + } +} + +button.btn.version-switcher__button:hover { + text-decoration-skip: none; + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +button.btn.version-switcher__button:focus-visible { + outline: 2px solid var(--pst-color-accent) +} + +button.btn.version-switcher__button:active { + border-color: var(--pst-color-border); + color: var(--pst-color-text-base) +} + +.version-switcher__menu { + border-color: var(--pst-color-border); + border-radius: var(--bs-dropdown-border-radius) +} + +.version-switcher__menu a.list-group-item { + background-color: var(--pst-color-on-background); + color: var(--pst-color-text-base); + padding: .75rem 1.25rem +} + +.version-switcher__menu a.list-group-item:not(:last-child) { + border-bottom: 1px solid var(--pst-color-border) +} + +.version-switcher__menu a.list-group-item:hover { + text-decoration-skip: none; + background-color: var(--pst-color-surface); + color: var(--pst-color-link-hover); + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(1px, .0625rem); + text-decoration-thickness: max(3px, .1875rem, .12em); + text-underline-offset: .1578em +} + +.version-switcher__menu a.list-group-item.active { + box-shadow: inset max(3px, .1875rem, .12em) 0 0 var(--pst-color-primary); + color: var(--pst-color-primary); + font-weight: 600; + position: relative; + z-index: 1 +} + +.version-switcher__menu a.list-group-item.active span:before { + content: ""; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; + z-index: -1 +} + +.version-switcher__menu, +button.version-switcher__button { + font-size: 1.1em; + z-index: 1055 +} + +@media(min-width:960px) { + + .version-switcher__menu, + button.version-switcher__button { + font-size: unset + } +} + +nav.page-toc { + margin-bottom: 1rem +} + +.bd-toc .nav .nav, +.list-caption .nav { + display: none +} + +.bd-toc .nav .nav.visible, +.bd-toc .nav>.active>ul, +.list-caption .nav.visible, +.list-caption>.active>ul, +.toc-entry { + display: block +} + +.toc-entry a.nav-link, +.toc-entry a>code { + color: var(--pst-color-text-muted) +} + +.toc-entry a.nav-link { + display: block; + margin-left: -1rem; + padding: .125rem 0 .125rem 1rem; + text-decoration: none +} + +.toc-entry a.nav-link:hover { + text-decoration-skip: none; + background-color: transparent; + text-decoration: underline; + text-decoration-skip-ink: none; + text-decoration-thickness: max(3px, .1875rem, .12em) +} + +.toc-entry a.nav-link:active, +.toc-entry a.nav-link:hover { + color: var(--pst-color-link-hover) +} + +.toc-entry a.nav-link.active { + background-color: transparent; + box-shadow: inset max(3px, .1875rem, .12em) 0 0 var(--pst-color-primary); + color: var(--pst-color-primary); + font-weight: 600 +} + +.toc-entry a.nav-link.active:hover { + color: var(--pst-color-link-hover) +} + +div.deprecated, +div.versionadded, +div.versionchanged { + background-color: var(--pst-color-on-background); + border-left: .2rem solid; + border-color: var(--pst-color-info); + border-radius: .25rem; + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important; + margin: 1.5625em auto; + overflow: hidden; + padding: 0 .6rem; + page-break-inside: avoid; + position: relative; + vertical-align: middle +} + +div.deprecated>p, +div.versionadded>p, +div.versionchanged>p { + margin-bottom: .6rem; + margin-top: .6rem +} + +div.versionadded { + background-color: var(--pst-color-success-bg); + border-color: var(--pst-color-success) +} + +div.versionchanged { + background-color: var(--pst-color-warning-bg); + border-color: var(--pst-color-warning) +} + +div.deprecated { + background-color: var(--pst-color-danger-bg); + border-color: var(--pst-color-danger) +} + +span.versionmodified { + font-weight: 600 +} + +span.versionmodified:before { + color: var(--pst-color-info); + content: var(--pst-icon-versionmodified-default); + font: var(--fa-font-solid); + margin-right: .6rem +} + +span.versionmodified.added:before { + color: var(--pst-color-success); + content: var(--pst-icon-versionmodified-added) +} + +span.versionmodified.changed:before { + color: var(--pst-color-warning); + content: var(--pst-icon-versionmodified-changed) +} + +span.versionmodified.deprecated:before { + color: var(--pst-color-danger); + content: var(--pst-icon-versionmodified-deprecated) +} + +.sidebar-indices-items { + border-top: 1px solid var(--pst-color-border); + display: flex; + flex-direction: column +} + +@media(min-width:960px) { + .sidebar-indices-items { + border-top: none + } +} + +.sidebar-indices-items .sidebar-indices-items__title { + color: var(--pst-color-text-base); + font-size: var(--pst-sidebar-header-font-size); + font-weight: var(--pst-sidebar-header-font-weight); + margin-bottom: .5rem +} + +.sidebar-indices-items ul.indices-link { + list-style: none; + margin-right: -1rem; + padding: 0 +} + +.sidebar-indices-items ul.indices-link li>a { + color: var(--pst-color-text-muted); + display: block; + padding: .25rem 0 +} + +.sidebar-indices-items ul.indices-link li>a:hover { + background-color: transparent; + color: var(--pst-color-primary); + text-decoration: none +} + +.bd-sidebar-primary div#rtd-footer-container { + bottom: -1rem; + margin: -1rem; + position: sticky +} + +.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge { + font-family: var(--pst-font-family-base); + font-size: .9em; + max-width: unset; + position: unset +} + +.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .rst-current-version { + align-items: center; + background-color: var(--pst-color-background); + border-top: 1px solid var(--pst-color-border); + color: var(--pst-color-success); + display: flex; + gap: .2rem; + height: 2.5rem; + transition: background-color .2s ease-out +} + +.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .fa.fa-book { + color: var(--pst-color-text-muted); + margin-right: auto +} + +.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .fa.fa-book:after { + color: var(--pst-color-text-base); + content: "Read The Docs"; + font-family: var(--pst-font-family-base); + font-weight: var(--pst-admonition-font-weight-heading) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge .fa.fa-caret-down { + color: var(--pst-color-text-muted) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-versions.rst-badge.shift-up .rst-current-version { + border-bottom: 1px solid var(--pst-color-border) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-other-versions { + background-color: var(--pst-color-surface); + color: var(--pst-color-text-base) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-other-versions dl dd a { + color: var(--pst-color-text-muted) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-other-versions hr { + background-color: var(--pst-color-border) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-other-versions small a { + color: var(--pst-color-link) +} + +.bd-sidebar-primary div#rtd-footer-container .rst-other-versions input { + background-color: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + padding-left: .5rem +} + +.admonition, +div.admonition { + background-color: var(--pst-color-on-background); + border-left: .2rem solid; + border-color: var(--pst-color-info); + border-radius: .25rem; + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important; + margin: 1.5625em auto; + overflow: hidden; + padding: 0 .6rem .8rem; + page-break-inside: avoid +} + +.admonition :last-child, +div.admonition :last-child { + margin-bottom: 0 +} + +.admonition p.admonition-title~*, +div.admonition p.admonition-title~* { + margin-left: 1.4rem; + margin-right: 1.4rem +} + +.admonition>ol, +.admonition>ul, +div.admonition>ol, +div.admonition>ul { + margin-left: 1em +} + +.admonition>.admonition-title, +div.admonition>.admonition-title { + background-color: var(--pst-color-info-bg); + font-weight: var(--pst-admonition-font-weight-heading); + margin: 0 -.6rem; + padding: .4rem .6rem .4rem 2rem; + position: relative; + z-index: 1 +} + +.admonition>.admonition-title:before, +div.admonition>.admonition-title:before { + content: ""; + height: 100%; + left: 0; + pointer-events: none; + position: absolute; + top: 0; + width: 100%; + z-index: -1 +} + +.admonition>.admonition-title:after, +div.admonition>.admonition-title:after { + color: var(--pst-color-info); + content: var(--pst-icon-admonition-default); + font: var(--fa-font-solid); + height: 1rem; + left: .5rem; + line-height: inherit; + opacity: 1; + position: absolute; + width: 1rem +} + +.admonition>.admonition-title+*, +div.admonition>.admonition-title+* { + margin-top: .4em +} + +.admonition.attention, +div.admonition.attention { + border-color: var(--pst-color-attention) +} + +.admonition.attention>.admonition-title, +div.admonition.attention>.admonition-title { + background-color: var(--pst-color-attention-bg) +} + +.admonition.attention>.admonition-title:after, +div.admonition.attention>.admonition-title:after { + color: var(--pst-color-attention); + content: var(--pst-icon-admonition-attention) +} + +.admonition.caution, +div.admonition.caution { + border-color: var(--pst-color-warning) +} + +.admonition.caution>.admonition-title, +div.admonition.caution>.admonition-title { + background-color: var(--pst-color-warning-bg) +} + +.admonition.caution>.admonition-title:after, +div.admonition.caution>.admonition-title:after { + color: var(--pst-color-warning); + content: var(--pst-icon-admonition-caution) +} + +.admonition.warning, +div.admonition.warning { + border-color: var(--pst-color-warning) +} + +.admonition.warning>.admonition-title, +div.admonition.warning>.admonition-title { + background-color: var(--pst-color-warning-bg) +} + +.admonition.warning>.admonition-title:after, +div.admonition.warning>.admonition-title:after { + color: var(--pst-color-warning); + content: var(--pst-icon-admonition-warning) +} + +.admonition.danger, +div.admonition.danger { + border-color: var(--pst-color-danger) +} + +.admonition.danger>.admonition-title, +div.admonition.danger>.admonition-title { + background-color: var(--pst-color-danger-bg) +} + +.admonition.danger>.admonition-title:after, +div.admonition.danger>.admonition-title:after { + color: var(--pst-color-danger); + content: var(--pst-icon-admonition-danger) +} + +.admonition.error, +div.admonition.error { + border-color: var(--pst-color-danger) +} + +.admonition.error>.admonition-title, +div.admonition.error>.admonition-title { + background-color: var(--pst-color-danger-bg) +} + +.admonition.error>.admonition-title:after, +div.admonition.error>.admonition-title:after { + color: var(--pst-color-danger); + content: var(--pst-icon-admonition-error) +} + +.admonition.hint, +div.admonition.hint { + border-color: var(--pst-color-success) +} + +.admonition.hint>.admonition-title, +div.admonition.hint>.admonition-title { + background-color: var(--pst-color-success-bg) +} + +.admonition.hint>.admonition-title:after, +div.admonition.hint>.admonition-title:after { + color: var(--pst-color-success); + content: var(--pst-icon-admonition-hint) +} + +.admonition.tip, +div.admonition.tip { + border-color: var(--pst-color-success) +} + +.admonition.tip>.admonition-title, +div.admonition.tip>.admonition-title { + background-color: var(--pst-color-success-bg) +} + +.admonition.tip>.admonition-title:after, +div.admonition.tip>.admonition-title:after { + color: var(--pst-color-success); + content: var(--pst-icon-admonition-tip) +} + +.admonition.important, +div.admonition.important { + border-color: var(--pst-color-attention) +} + +.admonition.important>.admonition-title, +div.admonition.important>.admonition-title { + background-color: var(--pst-color-attention-bg) +} + +.admonition.important>.admonition-title:after, +div.admonition.important>.admonition-title:after { + color: var(--pst-color-attention); + content: var(--pst-icon-admonition-important) +} + +.admonition.note, +div.admonition.note { + border-color: var(--pst-color-info) +} + +.admonition.note>.admonition-title, +div.admonition.note>.admonition-title { + background-color: var(--pst-color-info-bg) +} + +.admonition.note>.admonition-title:after, +div.admonition.note>.admonition-title:after { + color: var(--pst-color-info); + content: var(--pst-icon-admonition-note) +} + +.admonition.seealso, +div.admonition.seealso { + border-color: var(--pst-color-success) +} + +.admonition.seealso>.admonition-title, +div.admonition.seealso>.admonition-title { + background-color: var(--pst-color-success-bg) +} + +.admonition.seealso>.admonition-title:after, +div.admonition.seealso>.admonition-title:after { + color: var(--pst-color-success); + content: var(--pst-icon-admonition-seealso) +} + +.admonition.admonition-todo, +div.admonition.admonition-todo { + border-color: var(--pst-color-secondary) +} + +.admonition.admonition-todo>.admonition-title, +div.admonition.admonition-todo>.admonition-title { + background-color: var(--pst-color-secondary-bg) +} + +.admonition.admonition-todo>.admonition-title:after, +div.admonition.admonition-todo>.admonition-title:after { + color: var(--pst-color-secondary); + content: var(--pst-icon-admonition-todo) +} + +.admonition.sidebar, +div.admonition.sidebar { + border-width: 0 0 0 .2rem; + clear: both; + float: right; + margin-left: .5rem; + margin-top: 0; + max-width: 40% +} + +.admonition.sidebar.attention, +.admonition.sidebar.important, +div.admonition.sidebar.attention, +div.admonition.sidebar.important { + border-color: var(--pst-color-attention) +} + +.admonition.sidebar.caution, +.admonition.sidebar.warning, +div.admonition.sidebar.caution, +div.admonition.sidebar.warning { + border-color: var(--pst-color-warning) +} + +.admonition.sidebar.danger, +.admonition.sidebar.error, +div.admonition.sidebar.danger, +div.admonition.sidebar.error { + border-color: var(--pst-color-danger) +} + +.admonition.sidebar.hint, +.admonition.sidebar.seealso, +.admonition.sidebar.tip, +div.admonition.sidebar.hint, +div.admonition.sidebar.seealso, +div.admonition.sidebar.tip { + border-color: var(--pst-color-success) +} + +.admonition.sidebar.note, +.admonition.sidebar.todo, +div.admonition.sidebar.note, +div.admonition.sidebar.todo { + border-color: var(--pst-color-info) +} + +.admonition.sidebar p.admonition-title~*, +div.admonition.sidebar p.admonition-title~* { + margin-left: 0; + margin-right: 0 +} + +aside.topic, +div.topic, +div.topic.contents, +nav.contents { + background-color: var(--pst-color-surface); + border-color: var(--pst-color-border); + border-radius: .25rem; + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important; + display: flex; + flex-direction: column; + padding: 1rem 1.25rem +} + +aside.topic .topic-title, +div.topic .topic-title, +div.topic.contents .topic-title, +nav.contents .topic-title { + margin: 0 0 .5rem +} + +aside.topic p, +div.topic p, +div.topic.contents p, +nav.contents p { + color: var(--pst-color-on-surface) !important +} + +aside.topic ul.simple, +div.topic ul.simple, +div.topic.contents ul.simple, +nav.contents ul.simple { + padding-left: 1rem +} + +aside.topic ul.simple ul, +div.topic ul.simple ul, +div.topic.contents ul.simple ul, +nav.contents ul.simple ul { + padding-left: 2em +} + +aside.sidebar { + background-color: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + border-radius: .25rem; + margin-left: .5rem; + padding: 0 +} + +aside.sidebar>:last-child { + padding-bottom: 1rem +} + +aside.sidebar p.sidebar-title { + border-bottom: 1px solid var(--pst-color-border); + font-family: var(--pst-font-family-heading); + font-weight: var(--pst-admonition-font-weight-heading); + margin-bottom: 0; + padding-bottom: .5rem; + padding-top: .5rem; + position: relative +} + +aside.sidebar>:not(.sidebar-title):first-child, +aside.sidebar>p.sidebar-title+* { + margin-top: 1rem +} + +aside.sidebar>* { + padding-left: 1rem; + padding-right: 1rem +} + +p.rubric { + display: flex; + flex-direction: column +} + +.seealso dd { + margin-bottom: 0; + margin-top: 0 +} + +table.field-list { + border-collapse: separate; + border-spacing: 10px; + margin-left: 1px +} + +table.field-list th.field-name { + background-color: var(--pst-color-surface); + padding: 1px 8px 1px 5px; + white-space: nowrap +} + +table.field-list td.field-body p { + font-style: italic +} + +table.field-list td.field-body p>strong { + font-style: normal +} + +table.field-list td.field-body blockquote { + border-left: none; + margin: 0 0 .3em; + padding-left: 30px +} + +.table.autosummary td:first-child { + white-space: nowrap +} + +.sig { + font-family: var(--pst-font-family-monospace) +} + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset +} + +.sig.c .k, +.sig.c .kt, +.sig.c .m, +.sig.c .s, +.sig.c .sc, +.sig.cpp .k, +.sig.cpp .kt, +.sig.cpp .m, +.sig.cpp .s, +.sig.cpp .sc { + color: var(--pst-color-text-base) +} + +.sig-name { + color: var(--pst-color-inline-code) +} + +.sig-param .default_value, +.sig-param .o { + color: var(--pst-color-text-muted); + font-weight: 400 +} + +dt:target, +span.highlighted { + background-color: var(--pst-color-target) +} + +.viewcode-back { + font-family: var(--pst-font-family-base) +} + +.viewcode-block:target { + background-color: var(--pst-color-target); + border-bottom: 1px solid var(--pst-color-border); + border-top: 1px solid var(--pst-color-border); + position: relative +} + +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) { + margin-bottom: 3rem +} + +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd { + margin-left: 2rem +} + +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dd>dl.simple>dt { + display: flex +} + +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl.field-list { + display: grid; + grid-template-columns: unset +} + +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt.field-even, +dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dt.field-odd { + background-color: var(--pst-color-surface); + margin-bottom: .1rem; + margin-top: .2rem +} + +div.highlight, +div.literal-block-wrapper, +div[class*=highlight-] { + border-radius: .25rem; + display: flex; + flex-direction: column; + width: unset +} + +div.literal-block-wrapper { + border: 1px solid var(--pst-color-border); + border-radius: .25rem +} + +div.literal-block-wrapper div.code-block-caption { + border-bottom: 1px solid var(--pst-color-border); + font-size: 1rem; + font-weight: var(--pst-font-weight-caption); + margin: 0; + padding: .5rem +} + +div.literal-block-wrapper div.code-block-caption a.headerlink { + font-size: inherit +} + +div.literal-block-wrapper div[class*=highlight-] { + border-radius: 0; + margin: 0 +} + +div.literal-block-wrapper div[class*=highlight-] pre { + border: none; + box-shadow: none +} + +code.literal { + background-color: var(--pst-color-surface); + border: 1px solid var(--pst-color-border); + border-radius: .25rem; + padding: .1rem .25rem +} + +a>code { + color: var(--pst-color-inline-code-links) +} + +html[data-theme=light] .highlight .nf { + color: #0078a1 !important +} + +span.linenos { + opacity: .8 !important +} + +figure a.headerlink { + font-size: inherit; + position: absolute +} + +figure:hover a.headerlink { + visibility: visible +} + +figure figcaption { + color: var(--pst-color-text-muted); + font-family: var(--pst-font-family-heading); + font-weight: var(--pst-font-weight-caption); + margin-left: auto; + margin-right: auto +} + +figure figcaption table.table { + margin-left: auto; + margin-right: auto; + width: fit-content +} + +dt.label>span.brackets:not(:only-child):before { + content: "[" +} + +dt.label>span.brackets:not(:only-child):after { + content: "]" +} + +a.footnote-reference { + font-size: small; + vertical-align: super +} + +aside.footnote { + margin-bottom: .5rem +} + +aside.footnote:last-child { + margin-bottom: 1rem +} + +aside.footnote span.backrefs, +aside.footnote span.label { + font-weight: 700 +} + +aside.footnote:target { + background-color: var(--pst-color-target) +} + +div.doctest>div.highlight span.gp, +span.linenos, +table.highlighttable td.linenos { + user-select: none; + -webkit-user-select: text; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none +} + +dd { + margin-bottom: 10px; + margin-left: 30px; + margin-top: 3px +} + +ol, +ul { + padding-inline-start: 2rem +} + +ol li>p:first-child, +ul li>p:first-child { + margin-bottom: .25rem; + margin-top: .25rem +} + +blockquote { + background-color: var(--pst-color-surface); + border-left: .25em solid var(--pst-color-border); + border-radius: .25rem; + color: var(--pst-color-text-muted); + padding: 1em; + position: relative +} + +blockquote p { + color: var(--pst-color-text-base) +} + +blockquote .line-block { + margin: 0 +} + +blockquote p:last-child { + margin-bottom: 0 +} + +blockquote:before { + content: ""; + height: 100%; + left: 0; + pointer-events: none; + position: absolute; + top: 0; + width: 100%; + z-index: -1 +} + +span.guilabel { + background-color: var(--pst-color-info-bg); + border: 1px solid var(--pst-color-info); + border-radius: 4px; + color: var(--pst-color-info); + font-size: 80%; + font-weight: 700; + margin: auto 2px; + padding: 2.4px 6px; + position: relative +} + +span.guilabel:before { + content: ""; + height: 100%; + left: 0; + pointer-events: none; + position: absolute; + top: 0; + width: 100%; + z-index: -1 +} + +a.reference.download:before { + color: var(--pst-color-text-muted); + content: var(--pst-icon-download); + font: var(--fa-font-solid); + font-size: .8em; + padding: 0 .25em +} + +table { + display: table; + margin-left: auto; + margin-right: auto; + overflow: auto +} + +table.table-right { + margin-right: 0 +} + +table.table-left { + margin-left: 0 +} + +table caption { + caption-side: top; + color: var(--pst-color-text-muted); + text-align: center +} + +td.text-align\:left, +th.text-align\:left { + text-align: left +} + +td.text-align\:right, +th.text-align\:right { + text-align: right +} + +td.text-align\:center, +th.text-align\:center { + text-align: center +} + +.table { + --bs-table-bg: transparent +} + +.toctree-wrapper p.caption { + font-size: 1.5em; + margin-bottom: 0 +} + +.toctree-wrapper>ul { + padding-left: 0 +} + +.toctree-wrapper li[class^=toctree-l] { + list-style: none; + margin-bottom: .2em +} + +.toctree-wrapper li[class^=toctree-l]>a { + font-size: 1.1em; + list-style: none +} + +.toctree-wrapper li[class^=toctree-l]>ul { + list-style: none; + padding-inline-start: 1.5em +} + +.toctree-wrapper .toctree-l1>a { + font-size: 1.3em +} + +div.topic.contents ul.simple, +nav.contents ul.simple { + list-style: none; + padding-left: 0 +} + +div.math, +span.math { + align-items: center; + display: flex; + max-width: 100%; + overflow: hidden +} + +span.math { + display: inline-flex +} + +div.math { + flex-direction: row-reverse; + gap: .5em +} + +div.math span.eqno a.headerlink { + font-size: 1em; + position: relative +} + +div.math mjx-container { + flex-grow: 1; + overflow: auto; + padding-bottom: .2rem +} + +div.math mjx-container mjx-assistive-mml { + height: 0 +} + +.ablog-sidebar-item h2, +.ablog-sidebar-item h3 { + font-size: var(--pst-sidebar-header-font-size); + margin-top: .5rem +} + +.ablog-sidebar-item h2 a, +.ablog-sidebar-item h3 a { + color: var(--pst-color-text-base) +} + +.ablog-sidebar-item ul { + display: flex; + flex-direction: column; + gap: .5em; + list-style: none; + margin-bottom: 0; + overflow-y: hidden; + padding-left: 0 +} + +.ablog-sidebar-item ul.ablog-cloud { + flex-direction: row; + flex-flow: wrap; + gap: .5rem +} + +.ablog-sidebar-item ul.ablog-cloud li { + align-items: center; + display: flex +} + +.ablog__prev-next { + display: flex; + font-size: 1.2em; + padding: 1rem 0 +} + +.ablog__prev-next>span { + display: flex; + max-width: 45% +} + +.ablog__prev-next>span a { + align-items: center; + display: flex; + gap: 1rem; + line-height: 1.5rem; + margin-left: auto +} + +.ablog__prev-next>span a i:before { + color: var(--pst-color-text-base) +} + +.ablog__prev-next span.ablog__prev i.fa-arrow-circle-left:before { + content: var(--pst-icon-angle-left) +} + +.ablog__prev-next span.ablog__spacer { + display: none +} + +.ablog__prev-next span.ablog__next { + margin-left: auto; + text-align: right +} + +.ablog__prev-next span.ablog__next i.fa-arrow-circle-right:before { + content: var(--pst-icon-angle-right) +} + +.ablog__collection, +.postlist { + padding-left: 0 +} + +.ablog__collection .ablog-post, +.postlist .ablog-post { + list-style: none +} + +.ablog__collection .ablog-post .ablog-archive, +.postlist .ablog-post .ablog-archive { + display: flex; + flex-direction: row; + flex-wrap: wrap; + font-size: .75rem; + gap: 1rem; + list-style: none; + padding-left: 0 +} + +.ablog__collection .ablog-post .ablog-post-title, +.postlist .ablog-post .ablog-post-title { + font-size: 1.25rem; + margin-top: 0 +} + +.ablog__collection .ablog-post .ablog-post-title a, +.postlist .ablog-post .ablog-post-title a { + font-weight: 700 +} + +.ablog__collection .ablog-post .ablog-post-expand, +.postlist .ablog-post .ablog-post-expand { + margin-bottom: .5rem +} + +.docutils.container { + margin-left: unset; + margin-right: unset; + max-width: unset; + padding-left: unset; + padding-right: unset; + width: unset +} + +div.highlight button.copybtn { + align-items: center; + background-color: unset; + background-color: var(--pst-color-surface); + border: none; + display: flex; + justify-content: center +} + +div.highlight button.copybtn:not(.success) { + color: var(--pst-color-muted) +} + +div.highlight button.copybtn:hover:not(.success) { + background-color: var(--pst-color-shadow); + color: var(--pst-color-text) +} + +div.highlight button.copybtn.o-tooltip--left:after { + background-color: var(--pst-color-surface); + color: var(--pst-color-text) +} + +#ethical-ad-placement .ethical-footer a, +#ethical-ad-placement .ethical-footer a:active, +#ethical-ad-placement .ethical-footer a:hover, +#ethical-ad-placement .ethical-footer a:visited, +#ethical-ad-placement .ethical-sidebar a, +#ethical-ad-placement .ethical-sidebar a:active, +#ethical-ad-placement .ethical-sidebar a:hover, +#ethical-ad-placement .ethical-sidebar a:visited { + color: var(--pst-color-text-base) +} + +#ethical-ad-placement .ethical-footer, +#ethical-ad-placement .ethical-sidebar { + background-color: var(--pst-color-background); + border: 1px solid var(--pst-color-border); + border-radius: 5px; + color: var(--pst-color-text-base); + font-size: 14px; + line-height: 20px +} + +.bd-content div.jupyter_container { + background-color: unset; + border: none; + box-shadow: none +} + +.bd-content div.jupyter_container div.highlight, +.bd-content div.jupyter_container div.output { + border-radius: .25rem +} + +.bd-content div.jupyter_container div.highlight { + background-color: var(--pst-color-surface) +} + +.bd-content div.jupyter_container .cell_input, +.bd-content div.jupyter_container .cell_output { + border-radius: .25rem +} + +.bd-content div.jupyter_container .cell_input pre, +.bd-content div.jupyter_container .cell_output pre { + padding: 1rem +} + +.xr-wrap[hidden] { + display: block !important +} + +:root { + --pst-teal-50: #f4fbfc; + --pst-teal-100: #e9f6f8; + --pst-teal-200: #d0ecf1; + --pst-teal-300: #abdde6; + --pst-teal-400: #3fb1c5; + --pst-teal-500: #0a7d91; + --pst-teal-600: #085d6c; + --pst-teal-700: #064752; + --pst-teal-800: #042c33; + --pst-teal-900: #021b1f; + --pst-violet-50: #f4eefb; + --pst-violet-100: #e0c7ff; + --pst-violet-200: #d5b4fd; + --pst-violet-300: #b780ff; + --pst-violet-400: #9c5ffd; + --pst-violet-500: #8045e5; + --pst-violet-600: #6432bd; + --pst-violet-700: #4b258f; + --pst-violet-800: #341a61; + --pst-violet-900: #1e0e39; + --pst-gray-50: #f9f9fa; + --pst-gray-100: #f3f4f5; + --pst-gray-200: #e5e7ea; + --pst-gray-300: #d1d5da; + --pst-gray-400: #9ca4af; + --pst-gray-500: #677384; + --pst-gray-600: #48566b; + --pst-gray-700: #29313d; + --pst-gray-800: #222832; + --pst-gray-900: #14181e; + --pst-pink-50: #fcf8fd; + --pst-pink-100: #fcf0fa; + --pst-pink-200: #f8dff5; + --pst-pink-300: #f3c7ee; + --pst-pink-400: #e47fd7; + --pst-pink-500: #c132af; + --pst-pink-600: #912583; + --pst-pink-700: #6e1c64; + --pst-pink-800: #46123f; + --pst-pink-900: #2b0b27; + --pst-foundation-white: #fff; + --pst-foundation-black: #14181e +} + +html:not([data-theme]) { + --pst-color-primary: #0a7d91; + --pst-color-primary-bg: #d0ecf1; + --pst-color-secondary: #8045e5; + --pst-color-secondary-bg: #e0c7ff; + --pst-color-accent: #c132af; + --pst-color-accent-bg: #f8dff5; + --pst-color-info: #276be9; + --pst-color-info-bg: #dce7fc; + --pst-color-warning: #f66a0a; + --pst-color-warning-bg: #f8e3d0; + --pst-color-success: #00843f; + --pst-color-success-bg: #d6ece1; + --pst-color-attention: var(--pst-color-warning); + --pst-color-attention-bg: var(--pst-color-warning-bg); + --pst-color-danger: #d72d47; + --pst-color-danger-bg: #f9e1e4; + --pst-color-text-base: #222832; + --pst-color-text-muted: #48566b; + --pst-color-heading-color: #fff; + --pst-color-shadow: rgba(0, 0, 0, .1); + --pst-color-border: #d1d5da; + --pst-color-border-muted: rgba(23, 23, 26, .2); + --pst-color-inline-code: #912583; + --pst-color-inline-code-links: #085d6c; + --pst-color-target: #f3cf95; + --pst-color-background: #fff; + --pst-color-on-background: #fff; + --pst-color-surface: #f3f4f5; + --pst-color-on-surface: #222832; + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: var(--pst-color-secondary) +} + +html:not([data-theme]) .only-dark, +html:not([data-theme]) .only-dark~figcaption { + display: none !important +} + +html[data-theme=light] { + --pst-color-primary-bg: #d0ecf1; + --pst-color-secondary-bg: #e0c7ff; + --pst-color-accent: #c132af; + --pst-color-accent-bg: #f8dff5; + --pst-color-info-bg: #dce7fc; + --pst-color-warning-bg: #f8e3d0; + --pst-color-success-bg: #d6ece1; + --pst-color-attention: var(--pst-color-warning); + --pst-color-attention-bg: var(--pst-color-warning-bg); + --pst-color-danger-bg: #f9e1e4; + --pst-color-text-base: #222832; + --pst-color-text-muted: #48566b; + --pst-color-heading-color: #fff; + --pst-color-shadow: rgba(0, 0, 0, .1); + --pst-color-border: #d1d5da; + --pst-color-border-muted: rgba(23, 23, 26, .2); + --pst-color-inline-code: #912583; + --pst-color-inline-code-links: #085d6c; + --pst-color-target: #f3cf95; + --pst-color-background: #fff; + --pst-color-on-background: #fff; + --pst-color-surface: #f3f4f5; + --pst-color-on-surface: #222832; + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: var(--pst-color-secondary); + color-scheme: light +} + +html[data-theme=light] .only-dark, +html[data-theme=light] .only-dark~figcaption { + display: none !important +} + +html[data-theme=dark] { + --pst-color-primary-bg: #042c33; + --pst-color-secondary-bg: #341a61; + --pst-color-accent: #e47fd7; + --pst-color-accent-bg: #46123f; + --pst-color-info-bg: #06245d; + --pst-color-warning-bg: #652a02; + --pst-color-success-bg: #002f17; + --pst-color-attention: var(--pst-color-warning); + --pst-color-attention-bg: var(--pst-color-warning-bg); + --pst-color-danger-bg: #4e111b; + --pst-color-text-base: #ced6dd; + --pst-color-text-muted: #9ca4af; + --pst-color-heading-color: #14181e; + --pst-color-shadow: rgba(0, 0, 0, .2); + --pst-color-border: #48566b; + --pst-color-border-muted: #29313d; + --pst-color-inline-code: #f3c7ee; + --pst-color-inline-code-links: #3fb1c5; + --pst-color-target: #675c04; + --pst-color-background: #14181e; + --pst-color-on-background: #222832; + --pst-color-surface: #29313d; + --pst-color-on-surface: #f3f4f5; + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: var(--pst-color-secondary); + color-scheme: dark +} + +html[data-theme=dark] .only-light, +html[data-theme=dark] .only-light~figcaption { + display: none !important +} + +html[data-theme=dark] img:not(.only-dark):not(.dark-light) { + filter: brightness(.8) contrast(1.2) +} + +html[data-theme=dark] .bd-content img:not(.only-dark):not(.dark-light) { + background: #fff; + border-radius: .25rem +} + +html[data-theme=dark] .MathJax_SVG * { + fill: var(--pst-color-text-base) +} + +.pst-color-primary { + color: var(--pst-color-primary) +} + +.pst-color-secondary { + color: var(--pst-color-secondary) +} + +.pst-color-accent { + color: var(--pst-color-accent) +} + +.pst-color-info { + color: var(--pst-color-info) +} + +.pst-color-warning { + color: var(--pst-color-warning) +} + +.pst-color-success { + color: var(--pst-color-success) +} + +.pst-color-attention { + color: var(--pst-color-attention) +} + +.pst-color-danger { + color: var(--pst-color-danger) +} + +.pst-color-text-base { + color: var(--pst-color-text-base) +} + +.pst-color-text-muted { + color: var(--pst-color-text-muted) +} + +.pst-color-heading-color { + color: var(--pst-color-heading-color) +} + +.pst-color-shadow { + color: var(--pst-color-shadow) +} + +.pst-color-border { + color: var(--pst-color-border) +} + +.pst-color-border-muted { + color: var(--pst-color-border-muted) +} + +.pst-color-inline-code { + color: var(--pst-color-inline-code) +} + +.pst-color-inline-code-links { + color: var(--pst-color-inline-code-links) +} + +.pst-color-target { + color: var(--pst-color-target) +} + +.pst-color-background { + color: var(--pst-color-background) +} + +.pst-color-on-background { + color: var(--pst-color-on-background) +} + +.pst-color-surface { + color: var(--pst-color-surface) +} + +.pst-color-on-surface { + color: var(--pst-color-on-surface) +} + +html[data-theme=light] { + --pst-color-primary: #0a7d91; + --pst-color-primary-text: #fff; + --pst-color-primary-highlight: #053f49; + --sd-color-primary: var(--pst-color-primary); + --sd-color-primary-text: var(--pst-color-primary-text); + --sd-color-primary-highlight: var(--pst-color-primary-highlight); + --sd-color-primary-bg: #d0ecf1; + --sd-color-primary-bg-text: #14181e; + --pst-color-secondary: #8045e5; + --pst-color-secondary-text: #fff; + --pst-color-secondary-highlight: #591bc2; + --sd-color-secondary: var(--pst-color-secondary); + --sd-color-secondary-text: var(--pst-color-secondary-text); + --sd-color-secondary-highlight: var(--pst-color-secondary-highlight); + --sd-color-secondary-bg: #e0c7ff; + --sd-color-secondary-bg-text: #14181e; + --pst-color-success: #00843f; + --pst-color-success-text: #fff; + --pst-color-success-highlight: #00381a; + --sd-color-success: var(--pst-color-success); + --sd-color-success-text: var(--pst-color-success-text); + --sd-color-success-highlight: var(--pst-color-success-highlight); + --sd-color-success-bg: #d6ece1; + --sd-color-success-bg-text: #14181e; + --pst-color-info: #276be9; + --pst-color-info-text: #fff; + --pst-color-info-highlight: #124ab1; + --sd-color-info: var(--pst-color-info); + --sd-color-info-text: var(--pst-color-info-text); + --sd-color-info-highlight: var(--pst-color-info-highlight); + --sd-color-info-bg: #dce7fc; + --sd-color-info-bg-text: #14181e; + --pst-color-warning: #f66a0a; + --pst-color-warning-text: #14181e; + --pst-color-warning-highlight: #ad4a06; + --sd-color-warning: var(--pst-color-warning); + --sd-color-warning-text: var(--pst-color-warning-text); + --sd-color-warning-highlight: var(--pst-color-warning-highlight); + --sd-color-warning-bg: #f8e3d0; + --sd-color-warning-bg-text: #14181e; + --pst-color-danger: #d72d47; + --pst-color-danger-text: #fff; + --pst-color-danger-highlight: #9a1d30; + --sd-color-danger: var(--pst-color-danger); + --sd-color-danger-text: var(--pst-color-danger-text); + --sd-color-danger-highlight: var(--pst-color-danger-highlight); + --sd-color-danger-bg: #f9e1e4; + --sd-color-danger-bg-text: #14181e; + --pst-color-light: #f3f4f5; + --pst-color-light-text: #14181e; + --pst-color-light-highlight: #c9ced2; + --sd-color-light: var(--pst-color-light); + --sd-color-light-text: var(--pst-color-light-text); + --sd-color-light-highlight: var(--pst-color-light-highlight); + --sd-color-light-bg: #f7f7f8; + --sd-color-light-bg-text: #14181e; + --pst-color-muted: #29313d; + --pst-color-muted-text: #fff; + --pst-color-muted-highlight: #0a0c0f; + --sd-color-muted: var(--pst-color-muted); + --sd-color-muted-text: var(--pst-color-muted-text); + --sd-color-muted-highlight: var(--pst-color-muted-highlight); + --sd-color-muted-bg: #5a6c86; + --sd-color-muted-bg-text: #fff; + --pst-color-dark: #222832; + --pst-color-dark-text: #fff; + --pst-color-dark-highlight: #030404; + --sd-color-dark: var(--pst-color-dark); + --sd-color-dark-text: var(--pst-color-dark-text); + --sd-color-dark-highlight: var(--pst-color-dark-highlight); + --pst-color-black: #14181e; + --pst-color-black-text: #fff; + --pst-color-black-highlight: #000; + --sd-color-black: var(--pst-color-black); + --sd-color-black-text: var(--pst-color-black-text); + --sd-color-black-highlight: var(--pst-color-black-highlight); + --pst-color-white: #fff; + --pst-color-white-text: #14181e; + --pst-color-white-highlight: #d9d9d9; + --sd-color-white: var(--pst-color-white); + --sd-color-white-text: var(--pst-color-white-text); + --sd-color-white-highlight: var(--pst-color-white-highlight) +} + +html[data-theme=dark] { + --pst-color-primary: #3fb1c5; + --pst-color-primary-text: #14181e; + --pst-color-primary-highlight: #2b7e8d; + --sd-color-primary: var(--pst-color-primary); + --sd-color-primary-text: var(--pst-color-primary-text); + --sd-color-primary-highlight: var(--pst-color-primary-highlight); + --sd-color-primary-bg: #042c33; + --sd-color-primary-bg-text: #fff; + --pst-color-secondary: #9c5ffd; + --pst-color-secondary-text: #14181e; + --pst-color-secondary-highlight: #6d13fc; + --sd-color-secondary: var(--pst-color-secondary); + --sd-color-secondary-text: var(--pst-color-secondary-text); + --sd-color-secondary-highlight: var(--pst-color-secondary-highlight); + --sd-color-secondary-bg: #341a61; + --sd-color-secondary-bg-text: #fff; + --pst-color-success: #5fb488; + --pst-color-success-text: #14181e; + --pst-color-success-highlight: #3f8762; + --sd-color-success: var(--pst-color-success); + --sd-color-success-text: var(--pst-color-success-text); + --sd-color-success-highlight: var(--pst-color-success-highlight); + --sd-color-success-bg: #002f17; + --sd-color-success-bg-text: #fff; + --pst-color-info: #79a3f2; + --pst-color-info-text: #14181e; + --pst-color-info-highlight: #3373eb; + --sd-color-info: var(--pst-color-info); + --sd-color-info-text: var(--pst-color-info-text); + --sd-color-info-highlight: var(--pst-color-info-highlight); + --sd-color-info-bg: #06245d; + --sd-color-info-bg-text: #fff; + --pst-color-warning: #ff9245; + --pst-color-warning-text: #14181e; + --pst-color-warning-highlight: #f86600; + --sd-color-warning: var(--pst-color-warning); + --sd-color-warning-text: var(--pst-color-warning-text); + --sd-color-warning-highlight: var(--pst-color-warning-highlight); + --sd-color-warning-bg: #652a02; + --sd-color-warning-bg-text: #fff; + --pst-color-danger: #e78894; + --pst-color-danger-text: #14181e; + --pst-color-danger-highlight: #da485b; + --sd-color-danger: var(--pst-color-danger); + --sd-color-danger-text: var(--pst-color-danger-text); + --sd-color-danger-highlight: var(--pst-color-danger-highlight); + --sd-color-danger-bg: #4e111b; + --sd-color-danger-bg-text: #fff; + --pst-color-light: #f3f4f5; + --pst-color-light-text: #14181e; + --pst-color-light-highlight: #c9ced2; + --sd-color-light: var(--pst-color-light); + --sd-color-light-text: var(--pst-color-light-text); + --sd-color-light-highlight: var(--pst-color-light-highlight); + --sd-color-light-bg: #a3abb2; + --sd-color-light-bg-text: #14181e; + --pst-color-muted: #f3f4f5; + --pst-color-muted-text: #14181e; + --pst-color-muted-highlight: #c9ced2; + --sd-color-muted: var(--pst-color-muted); + --sd-color-muted-text: var(--pst-color-muted-text); + --sd-color-muted-highlight: var(--pst-color-muted-highlight); + --sd-color-muted-bg: #1d222b; + --sd-color-muted-bg-text: #fff; + --pst-color-dark: #222832; + --pst-color-dark-text: #fff; + --pst-color-dark-highlight: #030404; + --sd-color-dark: var(--pst-color-dark); + --sd-color-dark-text: var(--pst-color-dark-text); + --sd-color-dark-highlight: var(--pst-color-dark-highlight); + --pst-color-black: #14181e; + --pst-color-black-text: #fff; + --pst-color-black-highlight: #000; + --sd-color-black: var(--pst-color-black); + --sd-color-black-text: var(--pst-color-black-text); + --sd-color-black-highlight: var(--pst-color-black-highlight); + --pst-color-white: #fff; + --pst-color-white-text: #14181e; + --pst-color-white-highlight: #d9d9d9; + --sd-color-white: var(--pst-color-white); + --sd-color-white-text: var(--pst-color-white-text); + --sd-color-white-highlight: var(--pst-color-white-highlight) +} + +html[data-theme=dark], +html[data-theme=light] { + --sd-color-card-border: var(--pst-color-border) +} + +html[data-theme=light] .sd-shadow-lg, +html[data-theme=light] .sd-shadow-md, +html[data-theme=light] .sd-shadow-sm, +html[data-theme=light] .sd-shadow-xs { + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important +} + +.bd-content .sd-card { + border: 1px solid var(--pst-color-border) +} + +.bd-content .sd-card .sd-card-header { + background-color: var(--pst-color-panel-background); + border-bottom: 1px solid var(--pst-color-border) +} + +.bd-content .sd-card .sd-card-footer { + border-top: 1px solid var(--pst-color-border) +} + +.bd-content .sd-card .sd-card-body, +.bd-content .sd-card .sd-card-footer { + background-color: var(--pst-color-panel-background) +} + +.bd-content .sd-tab-set>input:checked+label { + border-color: transparent transparent var(--pst-color-primary); + color: var(--pst-color-primary) +} + +.bd-content .sd-tab-set>input:not(:checked)+label:hover { + border-color: var(--pst-color-secondary); + color: var(--pst-color-secondary) +} + +.bd-content .sd-tab-set>label { + border-top: .125rem solid transparent; + color: var(--pst-color-text-muted); + padding-top: .5em +} + +html .bd-content .sd-tab-set>label:hover { + border-color: var(--pst-color-secondary); + color: var(--pst-color-secondary) +} + +details.sd-dropdown { + border: 0 !important; + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important +} + +details.sd-dropdown summary.sd-card-header { + border: 0 !important +} + +details.sd-dropdown summary.sd-card-header+div.sd-summary-content { + border: 0 +} + +details.sd-dropdown summary.sd-card-header { + --pst-sd-dropdown-color: var(--pst-gray-500); + --pst-sd-dropdown-bg-color: var(--pst-color-surface); + align-items: center; + background-color: var(--pst-sd-dropdown-bg-color) !important; + border-left: .2rem solid var(--pst-sd-dropdown-color) !important; + display: flex; + font-weight: 600; + padding-bottom: .5rem; + padding-top: .5rem; + position: relative +} + +details.sd-dropdown summary.sd-card-header+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-card-border) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-primary, +details.sd-dropdown summary.sd-card-header.sd-bg-primary+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-primary); + --pst-sd-dropdown-bg-color: var(--sd-color-primary-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-primary { + color: var(--sd-color-primary-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-secondary, +details.sd-dropdown summary.sd-card-header.sd-bg-secondary+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-secondary); + --pst-sd-dropdown-bg-color: var(--sd-color-secondary-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-secondary { + color: var(--sd-color-secondary-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-success, +details.sd-dropdown summary.sd-card-header.sd-bg-success+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-success); + --pst-sd-dropdown-bg-color: var(--sd-color-success-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-success { + color: var(--sd-color-success-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-info, +details.sd-dropdown summary.sd-card-header.sd-bg-info+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-info); + --pst-sd-dropdown-bg-color: var(--sd-color-info-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-info { + color: var(--sd-color-info-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-warning, +details.sd-dropdown summary.sd-card-header.sd-bg-warning+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-warning); + --pst-sd-dropdown-bg-color: var(--sd-color-warning-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-warning { + color: var(--sd-color-warning-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-danger, +details.sd-dropdown summary.sd-card-header.sd-bg-danger+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-danger); + --pst-sd-dropdown-bg-color: var(--sd-color-danger-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-danger { + color: var(--sd-color-danger-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-light, +details.sd-dropdown summary.sd-card-header.sd-bg-light+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-light); + --pst-sd-dropdown-bg-color: var(--sd-color-light-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-light { + color: var(--sd-color-light-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-muted, +details.sd-dropdown summary.sd-card-header.sd-bg-muted+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-muted); + --pst-sd-dropdown-bg-color: var(--sd-color-muted-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-muted { + color: var(--sd-color-muted-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-dark, +details.sd-dropdown summary.sd-card-header.sd-bg-dark+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-dark); + --pst-sd-dropdown-bg-color: var(--sd-color-dark-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-dark { + color: var(--sd-color-dark-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-black, +details.sd-dropdown summary.sd-card-header.sd-bg-black+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-black); + --pst-sd-dropdown-bg-color: var(--sd-color-black-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-black { + color: var(--sd-color-black-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header.sd-bg-white, +details.sd-dropdown summary.sd-card-header.sd-bg-white+div.sd-summary-content { + --pst-sd-dropdown-color: var(--sd-color-white); + --pst-sd-dropdown-bg-color: var(--sd-color-white-bg) +} + +details.sd-dropdown summary.sd-card-header.sd-bg-text-white { + color: var(--sd-color-white-bg-text) !important +} + +details.sd-dropdown summary.sd-card-header:before { + content: ""; + height: 100%; + left: 0; + pointer-events: none; + position: absolute; + top: 0; + width: 100%; + z-index: -1 +} + +details.sd-dropdown summary.sd-card-header+div.sd-summary-content { + background-color: var(--pst-color-on-background); + border-bottom-left-radius: calc(.25rem - 1px); + border-left: .2rem solid var(--pst-sd-dropdown-color) !important +} + +details.sd-dropdown summary.sd-card-header span.sd-summary-icon { + align-items: center; + color: var(--pst-sd-dropdown-color) !important; + display: inline-flex +} + +details.sd-dropdown summary.sd-card-header span.sd-summary-icon svg { + opacity: 1 +} + +details.sd-dropdown summary.sd-card-header .sd-summary-down, +details.sd-dropdown summary.sd-card-header .sd-summary-up { + top: .7rem +} + +.bd-content .admonition button.toggle-button { + color: inherit +} + +.bd-content details.toggle-details summary { + border-left: 3px solid var(--pst-color-primary) +} + +html div.rendered_html html .jp-RenderedHTMLCommon table { + table-layout: auto +} + +html[data-theme=dark] .bd-content .nboutput .output_area.rendered_html { + background-color: var(--pst-color-text-base); + border-radius: .25rem; + color: var(--pst-color-on-background); + padding: .5rem +} + +html[data-theme=dark] .bd-content .nboutput .output_area.stderr { + background: var(--pst-color-danger) +} + +div.nblast.container { + margin-bottom: 1rem +} + +div.cell_output .output { + max-width: 100%; + overflow-x: auto +} + +html[data-theme=dark] .bd-content div.cell_output .text_html, +html[data-theme=dark] .bd-content div.cell_output img { + background-color: var(--pst-color-text-base); + border-radius: .25rem; + color: var(--pst-color-on-background); + padding: .5rem +} + +.bd-content div.cell_input { + display: flex; + flex-direction: column; + justify-content: stretch +} + +.bd-content div.cell_input, +.bd-content div.output { + border-radius: .25rem +} + +.bd-content div.output table { + table-layout: auto +} + +html[data-theme=dark] .bd-content img.leaflet-tile.leaflet-tile-loaded { + border-radius: 0; + padding: 0 +} + +.bd-search-container div#search-results>h2 { + font-size: var(--pst-font-size-icon); + margin-top: 0 +} + +.bd-search-container div#search-results p.search-summary { + color: var(--pst-color-text-muted) +} + +.bd-search-container ul.search { + list-style: none; + margin: 0 +} + +.bd-search-container ul.search li { + background-image: none; + border-top: 1px solid var(--pst-color-text-muted); + margin: 1rem 0; + padding: 1rem 0 +} + +.bd-search-container ul.search li>a { + font-size: 1.2em +} + +.bd-search-container ul.search li div.context, +.bd-search-container ul.search li p.context { + color: var(--pst-color-text-base); + margin: .5em 0 0 +} + +.bd-search-container ul.search li div.context a:before, +.bd-search-container ul.search li p.context a:before { + color: var(--pst-color-text-muted); + content: "#"; + padding-right: .2em +} + +/*# sourceMappingURL=pydata-sphinx-theme.css.map*/ \ No newline at end of file diff --git a/doc/rst/_css_helpers/pydata-sphinx-theme-0.8.1_for_book-0.3.3.css b/doc/rst/_css_helpers/pydata-sphinx-theme-0.8.1_for_book-0.3.3.css deleted file mode 100644 index 1cc903f588..0000000000 --- a/doc/rst/_css_helpers/pydata-sphinx-theme-0.8.1_for_book-0.3.3.css +++ /dev/null @@ -1,11883 +0,0 @@ -/*! - * Bootstrap v4.6.1 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -:root { - --blue: #007bff; - --indigo: #6610f2; - --purple: #6f42c1; - --pink: #e83e8c; - --red: #dc3545; - --orange: #fd7e14; - --yellow: #ffc107; - --green: #28a745; - --teal: #20c997; - --cyan: #17a2b8; - --white: #fff; - --gray: #6c757d; - --gray-dark: #343a40; - --primary: #007bff; - --secondary: #6c757d; - --success: #28a745; - --info: #17a2b8; - --warning: #ffc107; - --danger: #dc3545; - --light: #f8f9fa; - --dark: #343a40; - --breakpoint-xs: 0; - --breakpoint-sm: 540px; - --breakpoint-md: 720px; - --breakpoint-lg: 960px; - --breakpoint-xl: 1200px; - --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation 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: rgba(0, 0, 0, 0) -} - -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, Liberation Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; - font-size: 1rem; - line-height: 1.5; - color: #212529; - text-align: left -} - -[tabindex="-1"]:focus:not(:focus-visible) { - 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 { - font-style: normal; - line-height: inherit -} - -address, -dl, -ol, -ul { - margin-bottom: 1rem -} - -dl, -ol, -ul { - margin-top: 0 -} - -ol ol, -ol ul, -ul ol, -ul ul { - margin-bottom: 0 -} - -dt { - font-weight: 700 -} - -dd { - margin-bottom: .5rem; - margin-left: 0 -} - -blockquote { - margin: 0 0 1rem -} - -b, -strong { - font-weight: bolder -} - -small { - font-size: 80% -} - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline -} - -sub { - bottom: -.25em -} - -sup { - top: -.5em -} - -a { - color: #007bff; - background-color: transparent -} - -a:hover { - color: #0056b3 -} - -a:not([href]):not([class]), -a:not([href]):not([class]):hover { - color: inherit; - text-decoration: none -} - -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; - -ms-overflow-style: scrollbar -} - -figure { - margin: 0 0 1rem -} - -img { - border-style: none -} - -img, -svg { - vertical-align: middle -} - -svg { - overflow: hidden -} - -table { - border-collapse: collapse -} - -caption { - padding-top: .75rem; - padding-bottom: .75rem; - color: #6c757d; - text-align: left; - caption-side: bottom -} - -th { - text-align: inherit; - text-align: -webkit-match-parent -} - -label { - display: inline-block; - margin-bottom: .5rem -} - -button { - border-radius: 0 -} - -button:focus:not(:focus-visible) { - outline: 0 -} - -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 -} - -[role=button] { - cursor: pointer -} - -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 -} - -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 -} - -.display-1, -.display-2 { - font-weight: 300; - line-height: 1.2 -} - -.display-2 { - font-size: 5.5rem -} - -.display-3 { - font-size: 4.5rem -} - -.display-3, -.display-4 { - font-weight: 300; - line-height: 1.2 -} - -.display-4 { - font-size: 3.5rem -} - -hr { - margin-top: 1rem; - margin-bottom: 1rem; - 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-inline, -.list-unstyled { - 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, -.img-thumbnail { - max-width: 100%; - height: auto -} - -.img-thumbnail { - padding: .25rem; - background-color: #fff; - border: 1px solid #dee2e6; - border-radius: .25rem -} - -.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-wrap: 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, -.container-fluid, -.container-lg, -.container-md, -.container-sm, -.container-xl { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto -} - -@media (min-width:540px) { - - .container, - .container-sm { - max-width: 540px - } -} - -@media (min-width:720px) { - - .container, - .container-md, - .container-sm { - max-width: 720px - } -} - -@media (min-width:960px) { - - .container, - .container-lg, - .container-md, - .container-sm { - max-width: 960px - } -} - -@media (min-width:1200px) { - - .container, - .container-lg, - .container-md, - .container-sm, - .container-xl { - max-width: 1400px - } -} - -.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-2, -.col-3, -.col-4, -.col-5, -.col-6, -.col-7, -.col-8, -.col-9, -.col-10, -.col-11, -.col-12, -.col-auto, -.col-lg, -.col-lg-1, -.col-lg-2, -.col-lg-3, -.col-lg-4, -.col-lg-5, -.col-lg-6, -.col-lg-7, -.col-lg-8, -.col-lg-9, -.col-lg-10, -.col-lg-11, -.col-lg-12, -.col-lg-auto, -.col-md, -.col-md-1, -.col-md-2, -.col-md-3, -.col-md-4, -.col-md-5, -.col-md-6, -.col-md-7, -.col-md-8, -.col-md-9, -.col-md-10, -.col-md-11, -.col-md-12, -.col-md-auto, -.col-sm, -.col-sm-1, -.col-sm-2, -.col-sm-3, -.col-sm-4, -.col-sm-5, -.col-sm-6, -.col-sm-7, -.col-sm-8, -.col-sm-9, -.col-sm-10, -.col-sm-11, -.col-sm-12, -.col-sm-auto, -.col-xl, -.col-xl-1, -.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-10, -.col-xl-11, -.col-xl-12, -.col-xl-auto { - position: relative; - width: 100%; - padding-right: 15px; - padding-left: 15px -} - -.col { - flex-basis: 0; - flex-grow: 1; - max-width: 100% -} - -.row-cols-1>* { - flex: 0 0 100%; - max-width: 100% -} - -.row-cols-2>* { - flex: 0 0 50%; - max-width: 50% -} - -.row-cols-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% -} - -.row-cols-4>* { - flex: 0 0 25%; - max-width: 25% -} - -.row-cols-5>* { - flex: 0 0 20%; - max-width: 20% -} - -.row-cols-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% -} - -.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:540px) { - .col-sm { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-sm-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-sm-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-sm-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-sm-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-sm-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-sm-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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:720px) { - .col-md { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-md-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-md-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-md-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-md-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-md-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-md-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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:960px) { - .col-lg { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-lg-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-lg-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-lg-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-lg-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-lg-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-lg-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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% - } - - .row-cols-xl-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-xl-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-xl-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-xl-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-xl-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-xl-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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, -.table-bordered td, -.table-bordered th { - border: 1px solid #dee2e6 -} - -.table-bordered thead td, -.table-bordered thead th { - border-bottom-width: 2px -} - -.table-borderless tbody+tbody, -.table-borderless td, -.table-borderless th, -.table-borderless thead th { - border: 0 -} - -.table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(0, 0, 0, .05) -} - -.table-hover tbody tr:hover { - color: #212529; - background-color: rgba(0, 0, 0, .075) -} - -.table-primary, -.table-primary>td, -.table-primary>th { - background-color: #b8daff -} - -.table-primary tbody+tbody, -.table-primary td, -.table-primary th, -.table-primary thead th { - border-color: #7abaff -} - -.table-hover .table-primary:hover, -.table-hover .table-primary:hover>td, -.table-hover .table-primary:hover>th { - background-color: #9fcdff -} - -.table-secondary, -.table-secondary>td, -.table-secondary>th { - background-color: #d6d8db -} - -.table-secondary tbody+tbody, -.table-secondary td, -.table-secondary th, -.table-secondary thead th { - border-color: #b3b7bb -} - -.table-hover .table-secondary:hover, -.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, -.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, -.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, -.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, -.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, -.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, -.table-hover .table-dark:hover>td, -.table-hover .table-dark:hover>th { - background-color: #b9bbbe -} - -.table-active, -.table-active>td, -.table-active>th, -.table-hover .table-active:hover, -.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: hsla(0, 0%, 100%, .05) -} - -.table-dark.table-hover tbody tr:hover { - color: #fff; - background-color: hsla(0, 0%, 100%, .075) -} - -@media (max-width:539.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:719.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:959.98px) { - .table-responsive-lg { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch - } - - .table-responsive-lg>.table-bordered { - border: 0 - } -} - -@media (max-width:1199.98px) { - .table-responsive-xl { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch - } - - .table-responsive-xl>.table-bordered { - border: 0 - } -} - -.table-responsive { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch -} - -.table-responsive>.table-bordered { - border: 0 -} - -.form-control { - display: block; - width: 100%; - height: calc(1.5em + .75rem + 2px); - padding: .375rem .75rem; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #495057; - background-color: #fff; - background-clip: padding-box; - border: 1px solid #ced4da; - border-radius: .25rem; - transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out -} - -@media (prefers-reduced-motion:reduce) { - .form-control { - transition: none - } -} - -.form-control::-ms-expand { - background-color: transparent; - border: 0 -} - -.form-control:focus { - color: #495057; - background-color: #fff; - border-color: #80bdff; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.form-control::placeholder { - color: #6c757d; - opacity: 1 -} - -.form-control:disabled, -.form-control[readonly] { - background-color: #e9ecef; - opacity: 1 -} - -input[type=date].form-control, -input[type=datetime-local].form-control, -input[type=month].form-control, -input[type=time].form-control { - appearance: none -} - -select.form-control:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #495057 -} - -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: .375rem 0; - margin-bottom: 0; - font-size: 1rem; - 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], -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, -.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%; - left: 0; - 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-row>.col>.valid-tooltip, -.form-row>[class*=col-]>.valid-tooltip { - left: 5px -} - -.is-valid~.valid-feedback, -.is-valid~.valid-tooltip, -.was-validated :valid~.valid-feedback, -.was-validated :valid~.valid-tooltip { - display: block -} - -.form-control.is-valid, -.was-validated .form-control:valid { - border-color: #28a745; - padding-right: calc(1.5em + .75rem) !important; - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='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: right calc(.375em + .1875rem) center; - 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) -} - -.was-validated select.form-control:valid, -select.form-control.is-valid { - padding-right: 3rem !important; - background-position: right 1.5rem center -} - -.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(.75em + 2.3125rem) !important; - background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat, #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='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") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat -} - -.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) -} - -.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: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, -.custom-file-input.is-valid~.custom-file-label, -.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label:before, -.was-validated .custom-file-input:valid~.custom-file-label { - border-color: #28a745 -} - -.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%; - left: 0; - 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-row>.col>.invalid-tooltip, -.form-row>[class*=col-]>.invalid-tooltip { - left: 5px -} - -.is-invalid~.invalid-feedback, -.is-invalid~.invalid-tooltip, -.was-validated :invalid~.invalid-feedback, -.was-validated :invalid~.invalid-tooltip { - display: block -} - -.form-control.is-invalid, -.was-validated .form-control:invalid { - border-color: #dc3545; - padding-right: calc(1.5em + .75rem) !important; - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: right calc(.375em + .1875rem) center; - 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) -} - -.was-validated select.form-control:invalid, -select.form-control.is-invalid { - padding-right: 3rem !important; - background-position: right 1.5rem center -} - -.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(.75em + 2.3125rem) !important; - background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat, #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat -} - -.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) -} - -.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: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, -.custom-file-input.is-invalid~.custom-file-label, -.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label:before, -.was-validated .custom-file-input:invalid~.custom-file-label { - border-color: #dc3545 -} - -.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:540px) { - .form-inline label { - justify-content: center - } - - .form-inline .form-group, - .form-inline label { - display: flex; - align-items: center; - margin-bottom: 0 - } - - .form-inline .form-group { - flex: 0 0 auto; - flex-flow: row wrap - } - - .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(0, 123, 255, .25) -} - -.btn.disabled, -.btn:disabled { - opacity: .65 -} - -.btn:not(:disabled):not(.disabled) { - cursor: pointer -} - -a.btn.disabled, -fieldset:disabled a.btn { - pointer-events: none -} - -.btn-primary { - color: #fff; - background-color: #007bff; - border-color: #007bff -} - -.btn-primary.focus, -.btn-primary:focus, -.btn-primary:hover { - color: #fff; - background-color: #0069d9; - border-color: #0062cc -} - -.btn-primary.focus, -.btn-primary:focus { - box-shadow: 0 0 0 .2rem rgba(38, 143, 255, .5) -} - -.btn-primary.disabled, -.btn-primary:disabled { - color: #fff; - background-color: #007bff; - border-color: #007bff -} - -.btn-primary:not(:disabled):not(.disabled).active, -.btn-primary:not(:disabled):not(.disabled):active, -.show>.btn-primary.dropdown-toggle { - color: #fff; - background-color: #0062cc; - border-color: #005cbf -} - -.btn-primary:not(:disabled):not(.disabled).active:focus, -.btn-primary:not(:disabled):not(.disabled):active:focus, -.show>.btn-primary.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(38, 143, 255, .5) -} - -.btn-secondary { - color: #fff; - background-color: #6c757d; - border-color: #6c757d -} - -.btn-secondary.focus, -.btn-secondary:focus, -.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.focus, -.btn-success:focus, -.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.focus, -.btn-info:focus, -.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.focus, -.btn-warning:focus, -.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.focus, -.btn-danger:focus, -.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.focus, -.btn-light:focus, -.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.focus, -.btn-dark:focus, -.btn-dark:hover { - color: #fff; - background-color: #23272b; - border-color: #1d2124 -} - -.btn-dark.focus, -.btn-dark:focus { - box-shadow: 0 0 0 .2rem rgba(82, 88, 93, .5) -} - -.btn-dark.disabled, -.btn-dark:disabled { - color: #fff; - background-color: #343a40; - border-color: #343a40 -} - -.btn-dark:not(:disabled):not(.disabled).active, -.btn-dark:not(:disabled):not(.disabled):active, -.show>.btn-dark.dropdown-toggle { - color: #fff; - background-color: #1d2124; - border-color: #171a1d -} - -.btn-dark:not(:disabled):not(.disabled).active:focus, -.btn-dark:not(:disabled):not(.disabled):active:focus, -.show>.btn-dark.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(82, 88, 93, .5) -} - -.btn-outline-primary { - color: #007bff; - border-color: #007bff -} - -.btn-outline-primary:hover { - color: #fff; - background-color: #007bff; - border-color: #007bff -} - -.btn-outline-primary.focus, -.btn-outline-primary:focus { - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .5) -} - -.btn-outline-primary.disabled, -.btn-outline-primary:disabled { - color: #007bff; - background-color: transparent -} - -.btn-outline-primary:not(:disabled):not(.disabled).active, -.btn-outline-primary:not(:disabled):not(.disabled):active, -.show>.btn-outline-primary.dropdown-toggle { - color: #fff; - background-color: #007bff; - border-color: #007bff -} - -.btn-outline-primary:not(:disabled):not(.disabled).active:focus, -.btn-outline-primary:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-primary.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .5) -} - -.btn-outline-secondary { - color: #6c757d; - border-color: #6c757d -} - -.btn-outline-secondary:hover { - color: #fff; - background-color: #6c757d; - border-color: #6c757d -} - -.btn-outline-secondary.focus, -.btn-outline-secondary:focus { - box-shadow: 0 0 0 .2rem rgba(108, 117, 125, .5) -} - -.btn-outline-secondary.disabled, -.btn-outline-secondary:disabled { - color: #6c757d; - background-color: transparent -} - -.btn-outline-secondary:not(:disabled):not(.disabled).active, -.btn-outline-secondary:not(:disabled):not(.disabled):active, -.show>.btn-outline-secondary.dropdown-toggle { - color: #fff; - background-color: #6c757d; - border-color: #6c757d -} - -.btn-outline-secondary:not(:disabled):not(.disabled).active:focus, -.btn-outline-secondary:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-secondary.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(108, 117, 125, .5) -} - -.btn-outline-success { - color: #28a745; - border-color: #28a745 -} - -.btn-outline-success:hover { - color: #fff; - background-color: #28a745; - border-color: #28a745 -} - -.btn-outline-success.focus, -.btn-outline-success:focus { - box-shadow: 0 0 0 .2rem rgba(40, 167, 69, .5) -} - -.btn-outline-success.disabled, -.btn-outline-success:disabled { - color: #28a745; - background-color: transparent -} - -.btn-outline-success:not(:disabled):not(.disabled).active, -.btn-outline-success:not(:disabled):not(.disabled):active, -.show>.btn-outline-success.dropdown-toggle { - color: #fff; - background-color: #28a745; - border-color: #28a745 -} - -.btn-outline-success:not(:disabled):not(.disabled).active:focus, -.btn-outline-success:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-success.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(40, 167, 69, .5) -} - -.btn-outline-info { - color: #17a2b8; - border-color: #17a2b8 -} - -.btn-outline-info:hover { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8 -} - -.btn-outline-info.focus, -.btn-outline-info:focus { - box-shadow: 0 0 0 .2rem rgba(23, 162, 184, .5) -} - -.btn-outline-info.disabled, -.btn-outline-info:disabled { - color: #17a2b8; - background-color: transparent -} - -.btn-outline-info:not(:disabled):not(.disabled).active, -.btn-outline-info:not(:disabled):not(.disabled):active, -.show>.btn-outline-info.dropdown-toggle { - color: #fff; - background-color: #17a2b8; - border-color: #17a2b8 -} - -.btn-outline-info:not(:disabled):not(.disabled).active:focus, -.btn-outline-info:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-info.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(23, 162, 184, .5) -} - -.btn-outline-warning { - color: #ffc107; - border-color: #ffc107 -} - -.btn-outline-warning:hover { - color: #212529; - background-color: #ffc107; - border-color: #ffc107 -} - -.btn-outline-warning.focus, -.btn-outline-warning:focus { - box-shadow: 0 0 0 .2rem rgba(255, 193, 7, .5) -} - -.btn-outline-warning.disabled, -.btn-outline-warning:disabled { - color: #ffc107; - background-color: transparent -} - -.btn-outline-warning:not(:disabled):not(.disabled).active, -.btn-outline-warning:not(:disabled):not(.disabled):active, -.show>.btn-outline-warning.dropdown-toggle { - color: #212529; - background-color: #ffc107; - border-color: #ffc107 -} - -.btn-outline-warning:not(:disabled):not(.disabled).active:focus, -.btn-outline-warning:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-warning.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(255, 193, 7, .5) -} - -.btn-outline-danger { - color: #dc3545; - border-color: #dc3545 -} - -.btn-outline-danger:hover { - color: #fff; - background-color: #dc3545; - border-color: #dc3545 -} - -.btn-outline-danger.focus, -.btn-outline-danger:focus { - box-shadow: 0 0 0 .2rem rgba(220, 53, 69, .5) -} - -.btn-outline-danger.disabled, -.btn-outline-danger:disabled { - color: #dc3545; - background-color: transparent -} - -.btn-outline-danger:not(:disabled):not(.disabled).active, -.btn-outline-danger:not(:disabled):not(.disabled):active, -.show>.btn-outline-danger.dropdown-toggle { - color: #fff; - background-color: #dc3545; - border-color: #dc3545 -} - -.btn-outline-danger:not(:disabled):not(.disabled).active:focus, -.btn-outline-danger:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-danger.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(220, 53, 69, .5) -} - -.btn-outline-light { - color: #f8f9fa; - border-color: #f8f9fa -} - -.btn-outline-light:hover { - color: #212529; - background-color: #f8f9fa; - border-color: #f8f9fa -} - -.btn-outline-light.focus, -.btn-outline-light:focus { - box-shadow: 0 0 0 .2rem rgba(248, 249, 250, .5) -} - -.btn-outline-light.disabled, -.btn-outline-light:disabled { - color: #f8f9fa; - background-color: transparent -} - -.btn-outline-light:not(:disabled):not(.disabled).active, -.btn-outline-light:not(:disabled):not(.disabled):active, -.show>.btn-outline-light.dropdown-toggle { - color: #212529; - background-color: #f8f9fa; - border-color: #f8f9fa -} - -.btn-outline-light:not(:disabled):not(.disabled).active:focus, -.btn-outline-light:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-light.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(248, 249, 250, .5) -} - -.btn-outline-dark { - color: #343a40; - border-color: #343a40 -} - -.btn-outline-dark:hover { - color: #fff; - background-color: #343a40; - border-color: #343a40 -} - -.btn-outline-dark.focus, -.btn-outline-dark:focus { - box-shadow: 0 0 0 .2rem rgba(52, 58, 64, .5) -} - -.btn-outline-dark.disabled, -.btn-outline-dark:disabled { - color: #343a40; - background-color: transparent -} - -.btn-outline-dark:not(:disabled):not(.disabled).active, -.btn-outline-dark:not(:disabled):not(.disabled):active, -.show>.btn-outline-dark.dropdown-toggle { - color: #fff; - background-color: #343a40; - border-color: #343a40 -} - -.btn-outline-dark:not(:disabled):not(.disabled).active:focus, -.btn-outline-dark:not(:disabled):not(.disabled):active:focus, -.show>.btn-outline-dark.dropdown-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(52, 58, 64, .5) -} - -.btn-link { - font-weight: 400; - color: #007bff; - text-decoration: none -} - -.btn-link:hover { - color: #0056b3 -} - -.btn-link.focus, -.btn-link:focus, -.btn-link:hover { - text-decoration: underline -} - -.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:540px) { - .dropdown-menu-sm-left { - right: auto; - left: 0 - } - - .dropdown-menu-sm-right { - right: 0; - left: auto - } -} - -@media (min-width:720px) { - .dropdown-menu-md-left { - right: auto; - left: 0 - } - - .dropdown-menu-md-right { - right: 0; - left: auto - } -} - -@media (min-width:960px) { - .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: ""; - 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: #e9ecef -} - -.dropdown-item.active, -.dropdown-item:active { - color: #fff; - text-decoration: none; - background-color: #007bff -} - -.dropdown-item.disabled, -.dropdown-item:disabled { - color: #adb5bd; - 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.active, -.btn-group-vertical>.btn:active, -.btn-group-vertical>.btn:focus, -.btn-group-vertical>.btn:hover, -.btn-group>.btn.active, -.btn-group>.btn:active, -.btn-group>.btn:focus, -.btn-group>.btn:hover { - 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-group>.btn input[type=checkbox], -.btn-group-toggle>.btn-group>.btn input[type=radio], -.btn-group-toggle>.btn input[type=checkbox], -.btn-group-toggle>.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%; - min-width: 0; - 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(: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.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label, -.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label:after, -.input-group.has-validation>.custom-select:nth-last-child(n+3), -.input-group.has-validation>.form-control:nth-last-child(n+3), -.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label, -.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label:after, -.input-group:not(.has-validation)>.custom-select:not(:last-child), -.input-group:not(.has-validation)>.form-control:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-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.has-validation>.input-group-append:nth-last-child(n+3)>.btn, -.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.input-group-text, -.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.btn, -.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.input-group-text, -.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-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; - z-index: 1; - display: block; - min-height: 1.5rem; - padding-left: 1.5rem; - color-adjust: exact -} - -.custom-control-inline { - display: inline-flex; - margin-right: 1rem -} - -.custom-control-input { - position: absolute; - left: 0; - z-index: -1; - width: 1rem; - height: 1.25rem; - opacity: 0 -} - -.custom-control-input:checked~.custom-control-label:before { - color: #fff; - border-color: #007bff; - background-color: #007bff -} - -.custom-control-input:focus~.custom-control-label:before { - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.custom-control-input:focus:not(:checked)~.custom-control-label:before { - border-color: #80bdff -} - -.custom-control-input:not(:disabled):active~.custom-control-label:before { - color: #fff; - background-color: #b3d7ff; - border-color: #b3d7ff -} - -.custom-control-input:disabled~.custom-control-label, -.custom-control-input[disabled]~.custom-control-label { - color: #6c757d -} - -.custom-control-input:disabled~.custom-control-label:before, -.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 { - pointer-events: none; - background-color: #fff; - border: 1px solid #adb5bd -} - -.custom-control-label:after, -.custom-control-label:before { - position: absolute; - top: .25rem; - left: -1.5rem; - display: block; - width: 1rem; - height: 1rem; - content: "" -} - -.custom-control-label:after { - background: 50%/50% 50% no-repeat -} - -.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;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3E%3C/svg%3E") -} - -.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:before { - border-color: #007bff; - background-color: #007bff -} - -.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:after { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4'%3E%3Cpath stroke='%23fff' d='M0 2h4'/%3E%3C/svg%3E") -} - -.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label:before { - background-color: rgba(0, 123, 255, .5) -} - -.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label:before { - background-color: rgba(0, 123, 255, .5) -} - -.custom-radio .custom-control-label:before { - border-radius: 50% -} - -.custom-radio .custom-control-input:checked~.custom-control-label:after { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='%23fff'/%3E%3C/svg%3E") -} - -.custom-radio .custom-control-input:disabled:checked~.custom-control-label:before { - background-color: rgba(0, 123, 255, .5) -} - -.custom-switch { - padding-left: 2.25rem -} - -.custom-switch .custom-control-label:before { - left: -2.25rem; - width: 1.75rem; - pointer-events: all; - border-radius: .5rem -} - -.custom-switch .custom-control-label:after { - top: calc(.25rem + 2px); - left: calc(-2.25rem + 2px); - width: calc(1rem - 4px); - height: calc(1rem - 4px); - background-color: #adb5bd; - border-radius: .5rem; - transition: 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(0, 123, 255, .5) -} - -.custom-select { - display: inline-block; - width: 100%; - height: calc(1.5em + .75rem + 2px); - padding: .375rem 1.75rem .375rem .75rem; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #495057; - vertical-align: middle; - background: #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat; - border: 1px solid #ced4da; - border-radius: .25rem; - appearance: none -} - -.custom-select:focus { - border-color: #80bdff; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.custom-select:focus::-ms-value { - color: #495057; - background-color: #fff -} - -.custom-select[multiple], -.custom-select[size]:not([size="1"]) { - height: auto; - padding-right: .75rem; - background-image: none -} - -.custom-select:disabled { - color: #6c757d; - background-color: #e9ecef -} - -.custom-select::-ms-expand { - display: none -} - -.custom-select:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #495057 -} - -.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 { - display: inline-block; - margin-bottom: 0 -} - -.custom-file, -.custom-file-input { - position: relative; - width: 100%; - height: calc(1.5em + .75rem + 2px) -} - -.custom-file-input { - z-index: 2; - margin: 0; - overflow: hidden; - opacity: 0 -} - -.custom-file-input:focus~.custom-file-label { - border-color: #80bdff; - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.custom-file-input:disabled~.custom-file-label, -.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 { - left: 0; - z-index: 1; - height: calc(1.5em + .75rem + 2px); - overflow: hidden; - font-weight: 400; - background-color: #fff; - border: 1px solid #ced4da; - border-radius: .25rem -} - -.custom-file-label, -.custom-file-label:after { - position: absolute; - top: 0; - right: 0; - padding: .375rem .75rem; - line-height: 1.5; - color: #495057 -} - -.custom-file-label:after { - bottom: 0; - z-index: 3; - display: block; - height: calc(1.5em + .75rem); - content: "Browse"; - background-color: #e9ecef; - border-left: inherit; - border-radius: 0 .25rem .25rem 0 -} - -.custom-range { - width: 100%; - height: 1.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(0, 123, 255, .25) -} - -.custom-range:focus::-moz-range-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.custom-range:focus::-ms-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.custom-range::-moz-focus-outer { - border: 0 -} - -.custom-range::-webkit-slider-thumb { - width: 1rem; - height: 1rem; - margin-top: -.25rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; - appearance: none -} - -@media (prefers-reduced-motion:reduce) { - .custom-range::-webkit-slider-thumb { - transition: none - } -} - -.custom-range::-webkit-slider-thumb:active { - background-color: #b3d7ff -} - -.custom-range::-webkit-slider-runnable-track { - width: 100%; - height: .5rem; - color: transparent; - cursor: pointer; - background-color: #dee2e6; - border-color: transparent; - border-radius: 1rem -} - -.custom-range::-moz-range-thumb { - width: 1rem; - height: 1rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; - appearance: none -} - -@media (prefers-reduced-motion:reduce) { - .custom-range::-moz-range-thumb { - transition: none - } -} - -.custom-range::-moz-range-thumb:active { - background-color: #b3d7ff -} - -.custom-range::-moz-range-track { - width: 100%; - height: .5rem; - color: transparent; - cursor: pointer; - background-color: #dee2e6; - border-color: transparent; - border-radius: 1rem -} - -.custom-range::-ms-thumb { - width: 1rem; - height: 1rem; - margin-top: 0; - margin-right: .2rem; - margin-left: .2rem; - background-color: #007bff; - border: 0; - border-radius: 1rem; - transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out; - appearance: none -} - -@media (prefers-reduced-motion:reduce) { - .custom-range::-ms-thumb { - transition: none - } -} - -.custom-range::-ms-thumb:active { - background-color: #b3d7ff -} - -.custom-range::-ms-track { - width: 100%; - height: .5rem; - color: transparent; - cursor: pointer; - background-color: transparent; - border-color: transparent; - border-width: .5rem -} - -.custom-range::-ms-fill-lower, -.custom-range::-ms-fill-upper { - background-color: #dee2e6; - border-radius: 1rem -} - -.custom-range::-ms-fill-upper { - margin-right: 15px -} - -.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-link { - margin-bottom: -1px; - border: 1px solid transparent; - border-top-left-radius: .25rem; - border-top-right-radius: .25rem -} - -.nav-tabs .nav-link:focus, -.nav-tabs .nav-link:hover { - border-color: #e9ecef #e9ecef #dee2e6 -} - -.nav-tabs .nav-link.disabled { - color: #6c757d; - background-color: transparent; - border-color: transparent -} - -.nav-tabs .nav-item.show .nav-link, -.nav-tabs .nav-link.active { - color: #495057; - background-color: #fff; - border-color: #dee2e6 #dee2e6 #fff -} - -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.nav-pills .nav-link { - border-radius: .25rem -} - -.nav-pills .nav-link.active, -.nav-pills .show>.nav-link { - color: #fff; - background-color: #007bff -} - -.nav-fill .nav-item, -.nav-fill>.nav-link { - flex: 1 1 auto; - text-align: center -} - -.nav-justified .nav-item, -.nav-justified>.nav-link { - flex-basis: 0; - flex-grow: 1; - text-align: center -} - -.tab-content>.tab-pane { - display: none -} - -.tab-content>.active { - display: block -} - -.navbar { - position: relative; - padding: .5rem 1rem -} - -.navbar, -.navbar .container, -.navbar .container-fluid, -.navbar .container-lg, -.navbar .container-md, -.navbar .container-sm, -.navbar .container-xl { - 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: 50%/100% 100% no-repeat -} - -.navbar-nav-scroll { - max-height: 75vh; - overflow-y: auto -} - -@media (max-width:539.98px) { - - .navbar-expand-sm>.container, - .navbar-expand-sm>.container-fluid, - .navbar-expand-sm>.container-lg, - .navbar-expand-sm>.container-md, - .navbar-expand-sm>.container-sm, - .navbar-expand-sm>.container-xl { - padding-right: 0; - padding-left: 0 - } -} - -@media (min-width:540px) { - .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, - .navbar-expand-sm>.container-lg, - .navbar-expand-sm>.container-md, - .navbar-expand-sm>.container-sm, - .navbar-expand-sm>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-sm .navbar-nav-scroll { - overflow: visible - } - - .navbar-expand-sm .navbar-collapse { - display: flex !important; - flex-basis: auto - } - - .navbar-expand-sm .navbar-toggler { - display: none - } -} - -@media (max-width:719.98px) { - - .navbar-expand-md>.container, - .navbar-expand-md>.container-fluid, - .navbar-expand-md>.container-lg, - .navbar-expand-md>.container-md, - .navbar-expand-md>.container-sm, - .navbar-expand-md>.container-xl { - padding-right: 0; - padding-left: 0 - } -} - -@media (min-width:720px) { - .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, - .navbar-expand-md>.container-lg, - .navbar-expand-md>.container-md, - .navbar-expand-md>.container-sm, - .navbar-expand-md>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-md .navbar-nav-scroll { - overflow: visible - } - - .navbar-expand-md .navbar-collapse { - display: flex !important; - flex-basis: auto - } - - .navbar-expand-md .navbar-toggler { - display: none - } -} - -@media (max-width:959.98px) { - - .navbar-expand-lg>.container, - .navbar-expand-lg>.container-fluid, - .navbar-expand-lg>.container-lg, - .navbar-expand-lg>.container-md, - .navbar-expand-lg>.container-sm, - .navbar-expand-lg>.container-xl { - padding-right: 0; - padding-left: 0 - } -} - -@media (min-width:960px) { - .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, - .navbar-expand-lg>.container-lg, - .navbar-expand-lg>.container-md, - .navbar-expand-lg>.container-sm, - .navbar-expand-lg>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-lg .navbar-nav-scroll { - overflow: visible - } - - .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, - .navbar-expand-xl>.container-lg, - .navbar-expand-xl>.container-md, - .navbar-expand-xl>.container-sm, - .navbar-expand-xl>.container-xl { - 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, - .navbar-expand-xl>.container-lg, - .navbar-expand-xl>.container-md, - .navbar-expand-xl>.container-sm, - .navbar-expand-xl>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-xl .navbar-nav-scroll { - overflow: visible - } - - .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, -.navbar-expand>.container-lg, -.navbar-expand>.container-md, -.navbar-expand>.container-sm, -.navbar-expand>.container-xl { - 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, -.navbar-expand>.container-lg, -.navbar-expand>.container-md, -.navbar-expand>.container-sm, -.navbar-expand>.container-xl { - flex-wrap: nowrap -} - -.navbar-expand .navbar-nav-scroll { - overflow: visible -} - -.navbar-expand .navbar-collapse { - display: flex !important; - flex-basis: auto -} - -.navbar-expand .navbar-toggler { - display: none -} - -.navbar-light .navbar-brand, -.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;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") -} - -.navbar-light .navbar-text { - color: rgba(0, 0, 0, .5) -} - -.navbar-light .navbar-text a, -.navbar-light .navbar-text a:focus, -.navbar-light .navbar-text a:hover { - color: rgba(0, 0, 0, .9) -} - -.navbar-dark .navbar-brand, -.navbar-dark .navbar-brand:focus, -.navbar-dark .navbar-brand:hover { - color: #fff -} - -.navbar-dark .navbar-nav .nav-link { - color: hsla(0, 0%, 100%, .5) -} - -.navbar-dark .navbar-nav .nav-link:focus, -.navbar-dark .navbar-nav .nav-link:hover { - color: hsla(0, 0%, 100%, .75) -} - -.navbar-dark .navbar-nav .nav-link.disabled { - color: hsla(0, 0%, 100%, .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: hsla(0, 0%, 100%, .5); - border-color: hsla(0, 0%, 100%, .1) -} - -.navbar-dark .navbar-toggler-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") -} - -.navbar-dark .navbar-text { - color: hsla(0, 0%, 100%, .5) -} - -.navbar-dark .navbar-text a, -.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 { - border-top: inherit; - border-bottom: inherit -} - -.card>.list-group:first-child { - border-top-width: 0; - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.card>.list-group:last-child { - border-bottom-width: 0; - border-bottom-right-radius: calc(.25rem - 1px); - border-bottom-left-radius: calc(.25rem - 1px) -} - -.card>.card-header+.list-group, -.card>.list-group+.card-footer { - border-top: 0 -} - -.card-body { - flex: 1 1 auto; - min-height: 1px; - padding: 1.25rem -} - -.card-title { - margin-bottom: .75rem -} - -.card-subtitle { - margin-top: -.375rem -} - -.card-subtitle, -.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-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-bottom: -.75rem; - border-bottom: 0 -} - -.card-header-pills, -.card-header-tabs { - margin-right: -.625rem; - margin-left: -.625rem -} - -.card-img-overlay { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - padding: 1.25rem; - border-radius: calc(.25rem - 1px) -} - -.card-img, -.card-img-bottom, -.card-img-top { - flex-shrink: 0; - width: 100% -} - -.card-img, -.card-img-top { - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.card-img, -.card-img-bottom { - border-bottom-right-radius: calc(.25rem - 1px); - border-bottom-left-radius: calc(.25rem - 1px) -} - -.card-deck .card { - margin-bottom: 15px -} - -@media (min-width:540px) { - .card-deck { - display: flex; - flex-flow: row wrap; - margin-right: -15px; - margin-left: -15px - } - - .card-deck .card { - flex: 1 0 0%; - margin-right: 15px; - margin-bottom: 0; - margin-left: 15px - } -} - -.card-group>.card { - margin-bottom: 15px -} - -@media (min-width:540px) { - .card-group { - display: flex; - 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:540px) { - .card-columns { - column-count: 3; - column-gap: 1.25rem; - orphans: 1; - widows: 1 - } - - .card-columns .card { - display: inline-block; - width: 100% - } -} - -.accordion { - overflow-anchor: none -} - -.accordion>.card { - overflow: hidden -} - -.accordion>.card:not(:last-of-type) { - border-bottom: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.accordion>.card:not(:first-of-type) { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.accordion>.card>.card-header { - border-radius: 0; - 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 { - float: left; - padding-right: .5rem; - color: #6c757d; - content: "/" -} - -.breadcrumb-item+.breadcrumb-item:hover:before { - text-decoration: underline; - 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: #007bff; - background-color: #fff; - border: 1px solid #dee2e6 -} - -.page-link:hover { - z-index: 2; - color: #0056b3; - text-decoration: none; - background-color: #e9ecef; - border-color: #dee2e6 -} - -.page-link:focus { - z-index: 3; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .25) -} - -.page-item:first-child .page-link { - margin-left: 0; - border-top-left-radius: .25rem; - border-bottom-left-radius: .25rem -} - -.page-item:last-child .page-link { - border-top-right-radius: .25rem; - border-bottom-right-radius: .25rem -} - -.page-item.active .page-link { - z-index: 3; - color: #fff; - background-color: #007bff; - border-color: #007bff -} - -.page-item.disabled .page-link { - color: #6c757d; - pointer-events: none; - cursor: auto; - background-color: #fff; - border-color: #dee2e6 -} - -.pagination-lg .page-link { - padding: .75rem 1.5rem; - font-size: 1.25rem; - line-height: 1.5 -} - -.pagination-lg .page-item:first-child .page-link { - border-top-left-radius: .3rem; - border-bottom-left-radius: .3rem -} - -.pagination-lg .page-item:last-child .page-link { - border-top-right-radius: .3rem; - border-bottom-right-radius: .3rem -} - -.pagination-sm .page-link { - padding: .25rem .5rem; - font-size: .875rem; - line-height: 1.5 -} - -.pagination-sm .page-item:first-child .page-link { - border-top-left-radius: .2rem; - border-bottom-left-radius: .2rem -} - -.pagination-sm .page-item:last-child .page-link { - border-top-right-radius: .2rem; - border-bottom-right-radius: .2rem -} - -.badge { - display: inline-block; - padding: .25em .4em; - font-size: 75%; - font-weight: 700; - line-height: 1; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25rem; - transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out -} - -@media (prefers-reduced-motion:reduce) { - .badge { - transition: none - } -} - -a.badge:focus, -a.badge:hover { - text-decoration: none -} - -.badge:empty { - display: none -} - -.btn .badge { - position: relative; - top: -1px -} - -.badge-pill { - padding-right: .6em; - padding-left: .6em; - border-radius: 10rem -} - -.badge-primary { - color: #fff; - background-color: #007bff -} - -a.badge-primary:focus, -a.badge-primary:hover { - color: #fff; - background-color: #0062cc -} - -a.badge-primary.focus, -a.badge-primary:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(0, 123, 255, .5) -} - -.badge-secondary { - color: #fff; - background-color: #6c757d -} - -a.badge-secondary:focus, -a.badge-secondary:hover { - color: #fff; - background-color: #545b62 -} - -a.badge-secondary.focus, -a.badge-secondary:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(108, 117, 125, .5) -} - -.badge-success { - color: #fff; - background-color: #28a745 -} - -a.badge-success:focus, -a.badge-success:hover { - color: #fff; - background-color: #1e7e34 -} - -a.badge-success.focus, -a.badge-success:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(40, 167, 69, .5) -} - -.badge-info { - color: #fff; - background-color: #17a2b8 -} - -a.badge-info:focus, -a.badge-info:hover { - color: #fff; - background-color: #117a8b -} - -a.badge-info.focus, -a.badge-info:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(23, 162, 184, .5) -} - -.badge-warning { - color: #212529; - background-color: #ffc107 -} - -a.badge-warning:focus, -a.badge-warning:hover { - color: #212529; - background-color: #d39e00 -} - -a.badge-warning.focus, -a.badge-warning:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 193, 7, .5) -} - -.badge-danger { - color: #fff; - background-color: #dc3545 -} - -a.badge-danger:focus, -a.badge-danger:hover { - color: #fff; - background-color: #bd2130 -} - -a.badge-danger.focus, -a.badge-danger:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(220, 53, 69, .5) -} - -.badge-light { - color: #212529; - background-color: #f8f9fa -} - -a.badge-light:focus, -a.badge-light:hover { - color: #212529; - background-color: #dae0e5 -} - -a.badge-light.focus, -a.badge-light:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(248, 249, 250, .5) -} - -.badge-dark { - color: #fff; - background-color: #343a40 -} - -a.badge-dark:focus, -a.badge-dark:hover { - color: #fff; - background-color: #1d2124 -} - -a.badge-dark.focus, -a.badge-dark:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(52, 58, 64, .5) -} - -.jumbotron { - padding: 2rem 1rem; - margin-bottom: 2rem; - background-color: #e9ecef; - border-radius: .3rem -} - -@media (min-width:540px) { - .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; - z-index: 2; - padding: .75rem 1.25rem; - color: inherit -} - -.alert-primary { - color: #004085; - background-color: #cce5ff; - border-color: #b8daff -} - -.alert-primary hr { - border-top-color: #9fcdff -} - -.alert-primary .alert-link { - color: #002752 -} - -.alert-secondary { - color: #383d41; - background-color: #e2e3e5; - border-color: #d6d8db -} - -.alert-secondary hr { - border-top-color: #c8cbcf -} - -.alert-secondary .alert-link { - color: #202326 -} - -.alert-success { - color: #155724; - background-color: #d4edda; - border-color: #c3e6cb -} - -.alert-success hr { - border-top-color: #b1dfbb -} - -.alert-success .alert-link { - color: #0b2e13 -} - -.alert-info { - color: #0c5460; - background-color: #d1ecf1; - border-color: #bee5eb -} - -.alert-info hr { - border-top-color: #abdde5 -} - -.alert-info .alert-link { - color: #062c33 -} - -.alert-warning { - color: #856404; - background-color: #fff3cd; - border-color: #ffeeba -} - -.alert-warning hr { - border-top-color: #ffe8a1 -} - -.alert-warning .alert-link { - color: #533f03 -} - -.alert-danger { - color: #721c24; - background-color: #f8d7da; - border-color: #f5c6cb -} - -.alert-danger hr { - border-top-color: #f1b0b7 -} - -.alert-danger .alert-link { - color: #491217 -} - -.alert-light { - color: #818182; - background-color: #fefefe; - border-color: #fdfdfe -} - -.alert-light hr { - border-top-color: #ececf6 -} - -.alert-light .alert-link { - color: #686868 -} - -.alert-dark { - color: #1b1e21; - background-color: #d6d8d9; - border-color: #c6c8ca -} - -.alert-dark hr { - border-top-color: #b9bbbe -} - -.alert-dark .alert-link { - color: #040505 -} - -@keyframes progress-bar-stripes { - 0% { - background-position: 1rem 0 - } - - to { - background-position: 0 0 - } -} - -.progress { - height: 1rem; - line-height: 0; - font-size: .75rem; - background-color: #e9ecef; - border-radius: .25rem -} - -.progress, -.progress-bar { - display: flex; - overflow: hidden -} - -.progress-bar { - flex-direction: column; - justify-content: center; - color: #fff; - text-align: center; - white-space: nowrap; - background-color: #007bff; - transition: width .6s ease -} - -@media (prefers-reduced-motion:reduce) { - .progress-bar { - transition: none - } -} - -.progress-bar-striped { - background-image: linear-gradient(45deg, hsla(0, 0%, 100%, .15) 25%, transparent 0, transparent 50%, hsla(0, 0%, 100%, .15) 0, hsla(0, 0%, 100%, .15) 75%, transparent 0, 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; - border-radius: .25rem -} - -.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; - background-color: #fff; - border: 1px solid rgba(0, 0, 0, .125) -} - -.list-group-item:first-child { - border-top-left-radius: inherit; - border-top-right-radius: inherit -} - -.list-group-item:last-child { - border-bottom-right-radius: inherit; - border-bottom-left-radius: inherit -} - -.list-group-item.disabled, -.list-group-item:disabled { - color: #6c757d; - pointer-events: none; - background-color: #fff -} - -.list-group-item.active { - z-index: 2; - color: #fff; - background-color: #007bff; - border-color: #007bff -} - -.list-group-item+.list-group-item { - border-top-width: 0 -} - -.list-group-item+.list-group-item.active { - margin-top: -1px; - border-top-width: 1px -} - -.list-group-horizontal { - flex-direction: row -} - -.list-group-horizontal>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 -} - -.list-group-horizontal>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 -} - -.list-group-horizontal>.list-group-item.active { - margin-top: 0 -} - -.list-group-horizontal>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 -} - -.list-group-horizontal>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px -} - -@media (min-width:540px) { - .list-group-horizontal-sm { - flex-direction: row - } - - .list-group-horizontal-sm>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-sm>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-sm>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-sm>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-sm>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width:720px) { - .list-group-horizontal-md { - flex-direction: row - } - - .list-group-horizontal-md>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-md>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-md>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-md>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-md>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width:960px) { - .list-group-horizontal-lg { - flex-direction: row - } - - .list-group-horizontal-lg>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-lg>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-lg>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-lg>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-lg>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width:1200px) { - .list-group-horizontal-xl { - flex-direction: row - } - - .list-group-horizontal-xl>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-xl>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-xl>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-xl>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-xl>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -.list-group-flush { - border-radius: 0 -} - -.list-group-flush>.list-group-item { - border-width: 0 0 1px -} - -.list-group-flush>.list-group-item:last-child { - border-bottom-width: 0 -} - -.list-group-item-primary { - color: #004085; - background-color: #b8daff -} - -.list-group-item-primary.list-group-item-action:focus, -.list-group-item-primary.list-group-item-action:hover { - color: #004085; - background-color: #9fcdff -} - -.list-group-item-primary.list-group-item-action.active { - color: #fff; - background-color: #004085; - border-color: #004085 -} - -.list-group-item-secondary { - color: #383d41; - background-color: #d6d8db -} - -.list-group-item-secondary.list-group-item-action:focus, -.list-group-item-secondary.list-group-item-action:hover { - color: #383d41; - background-color: #c8cbcf -} - -.list-group-item-secondary.list-group-item-action.active { - color: #fff; - background-color: #383d41; - border-color: #383d41 -} - -.list-group-item-success { - color: #155724; - background-color: #c3e6cb -} - -.list-group-item-success.list-group-item-action:focus, -.list-group-item-success.list-group-item-action:hover { - color: #155724; - background-color: #b1dfbb -} - -.list-group-item-success.list-group-item-action.active { - color: #fff; - background-color: #155724; - border-color: #155724 -} - -.list-group-item-info { - color: #0c5460; - background-color: #bee5eb -} - -.list-group-item-info.list-group-item-action:focus, -.list-group-item-info.list-group-item-action:hover { - color: #0c5460; - background-color: #abdde5 -} - -.list-group-item-info.list-group-item-action.active { - color: #fff; - background-color: #0c5460; - border-color: #0c5460 -} - -.list-group-item-warning { - color: #856404; - background-color: #ffeeba -} - -.list-group-item-warning.list-group-item-action:focus, -.list-group-item-warning.list-group-item-action:hover { - color: #856404; - background-color: #ffe8a1 -} - -.list-group-item-warning.list-group-item-action.active { - color: #fff; - background-color: #856404; - border-color: #856404 -} - -.list-group-item-danger { - color: #721c24; - background-color: #f5c6cb -} - -.list-group-item-danger.list-group-item-action:focus, -.list-group-item-danger.list-group-item-action:hover { - color: #721c24; - background-color: #f1b0b7 -} - -.list-group-item-danger.list-group-item-action.active { - color: #fff; - background-color: #721c24; - border-color: #721c24 -} - -.list-group-item-light { - color: #818182; - background-color: #fdfdfe -} - -.list-group-item-light.list-group-item-action:focus, -.list-group-item-light.list-group-item-action:hover { - color: #818182; - background-color: #ececf6 -} - -.list-group-item-light.list-group-item-action.active { - color: #fff; - background-color: #818182; - border-color: #818182 -} - -.list-group-item-dark { - color: #1b1e21; - background-color: #c6c8ca -} - -.list-group-item-dark.list-group-item-action:focus, -.list-group-item-dark.list-group-item-action:hover { - color: #1b1e21; - background-color: #b9bbbe -} - -.list-group-item-dark.list-group-item-action.active { - color: #fff; - background-color: #1b1e21; - border-color: #1b1e21 -} - -.close { - float: right; - font-size: 1.5rem; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - opacity: .5 -} - -.close:hover { - color: #000; - text-decoration: none -} - -.close:not(:disabled):not(.disabled):focus, -.close:not(:disabled):not(.disabled):hover { - opacity: .75 -} - -button.close { - padding: 0; - background-color: transparent; - border: 0 -} - -a.close.disabled { - pointer-events: none -} - -.toast { - flex-basis: 350px; - max-width: 350px; - font-size: .875rem; - background-color: hsla(0, 0%, 100%, .85); - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, .1); - box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .1); - 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: hsla(0, 0%, 100%, .85); - background-clip: padding-box; - border-bottom: 1px solid rgba(0, 0, 0, .05); - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.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: translateY(-50px) -} - -@media (prefers-reduced-motion:reduce) { - .modal.fade .modal-dialog { - transition: none - } -} - -.modal.show .modal-dialog { - transform: none -} - -.modal.modal-static .modal-dialog { - transform: scale(1.02) -} - -.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); - height: min-content; - 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; - border-bottom: 1px solid #dee2e6; - border-top-left-radius: calc(.3rem - 1px); - border-top-right-radius: calc(.3rem - 1px) -} - -.modal-header .close { - padding: 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; - flex-wrap: wrap; - align-items: center; - justify-content: flex-end; - padding: .75rem; - border-top: 1px solid #dee2e6; - border-bottom-right-radius: calc(.3rem - 1px); - border-bottom-left-radius: calc(.3rem - 1px) -} - -.modal-footer>* { - margin: .25rem -} - -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll -} - -@media (min-width:540px) { - .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); - height: min-content - } - - .modal-sm { - max-width: 300px - } -} - -@media (min-width:960px) { - - .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, Liberation 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 { - top: 0; - left: 0; - z-index: 1060; - max-width: 276px; - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, Liberation 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, -.popover .arrow { - position: absolute; - display: block -} - -.popover .arrow { - 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) -} - -.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); - 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) -} - -.bs-popover-auto[x-placement^=bottom]>.arrow:before, -.bs-popover-bottom>.arrow:before { - top: 0; - border-width: 0 .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; - 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); - 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: opacity 0s .6s -} - -@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%; - padding: 0; - color: #fff; - text-align: center; - background: none; - border: 0; - 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: 50%/100% 100% no-repeat -} - -.carousel-control-prev-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3E%3C/svg%3E") -} - -.carousel-control-next-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8'%3E%3Cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-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(1turn) - } -} - -.spinner-border { - display: inline-block; - width: 2rem; - height: 2rem; - vertical-align: -.125em; - border: .25em solid; - border-right: .25em solid 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; - transform: none - } -} - -.spinner-grow { - display: inline-block; - width: 2rem; - height: 2rem; - vertical-align: -.125em; - background-color: currentColor; - border-radius: 50%; - opacity: 0; - animation: spinner-grow .75s linear infinite -} - -.spinner-grow-sm { - width: 1rem; - height: 1rem -} - -@media (prefers-reduced-motion:reduce) { - - .spinner-border, - .spinner-grow { - animation-duration: 1.5s - } -} - -.align-baseline { - vertical-align: baseline !important -} - -.align-top { - vertical-align: top !important -} - -.align-middle { - vertical-align: middle !important -} - -.align-bottom { - vertical-align: bottom !important -} - -.align-text-bottom { - vertical-align: text-bottom !important -} - -.align-text-top { - vertical-align: text-top !important -} - -.bg-primary { - background-color: #007bff !important -} - -a.bg-primary:focus, -a.bg-primary:hover, -button.bg-primary:focus, -button.bg-primary:hover { - background-color: #0062cc !important -} - -.bg-secondary { - background-color: #6c757d !important -} - -a.bg-secondary:focus, -a.bg-secondary:hover, -button.bg-secondary:focus, -button.bg-secondary:hover { - background-color: #545b62 !important -} - -.bg-success { - background-color: #28a745 !important -} - -a.bg-success:focus, -a.bg-success:hover, -button.bg-success:focus, -button.bg-success:hover { - background-color: #1e7e34 !important -} - -.bg-info { - background-color: #17a2b8 !important -} - -a.bg-info:focus, -a.bg-info:hover, -button.bg-info:focus, -button.bg-info:hover { - background-color: #117a8b !important -} - -.bg-warning { - background-color: #ffc107 !important -} - -a.bg-warning:focus, -a.bg-warning:hover, -button.bg-warning:focus, -button.bg-warning:hover { - background-color: #d39e00 !important -} - -.bg-danger { - background-color: #dc3545 !important -} - -a.bg-danger:focus, -a.bg-danger:hover, -button.bg-danger:focus, -button.bg-danger:hover { - background-color: #bd2130 !important -} - -.bg-light { - background-color: #f8f9fa !important -} - -a.bg-light:focus, -a.bg-light:hover, -button.bg-light:focus, -button.bg-light:hover { - background-color: #dae0e5 !important -} - -.bg-dark { - background-color: #343a40 !important -} - -a.bg-dark:focus, -a.bg-dark:hover, -button.bg-dark:focus, -button.bg-dark:hover { - background-color: #1d2124 !important -} - -.bg-white { - background-color: #fff !important -} - -.bg-transparent { - background-color: transparent !important -} - -.border { - border: 1px solid #dee2e6 !important -} - -.border-top { - border-top: 1px solid #dee2e6 !important -} - -.border-right { - border-right: 1px solid #dee2e6 !important -} - -.border-bottom { - border-bottom: 1px solid #dee2e6 !important -} - -.border-left { - border-left: 1px solid #dee2e6 !important -} - -.border-0 { - border: 0 !important -} - -.border-top-0 { - border-top: 0 !important -} - -.border-right-0 { - border-right: 0 !important -} - -.border-bottom-0 { - border-bottom: 0 !important -} - -.border-left-0 { - border-left: 0 !important -} - -.border-primary { - border-color: #007bff !important -} - -.border-secondary { - border-color: #6c757d !important -} - -.border-success { - border-color: #28a745 !important -} - -.border-info { - border-color: #17a2b8 !important -} - -.border-warning { - border-color: #ffc107 !important -} - -.border-danger { - border-color: #dc3545 !important -} - -.border-light { - border-color: #f8f9fa !important -} - -.border-dark { - border-color: #343a40 !important -} - -.border-white { - border-color: #fff !important -} - -.rounded-sm { - border-radius: .2rem !important -} - -.rounded { - border-radius: .25rem !important -} - -.rounded-top { - border-top-left-radius: .25rem !important -} - -.rounded-right, -.rounded-top { - border-top-right-radius: .25rem !important -} - -.rounded-bottom, -.rounded-right { - border-bottom-right-radius: .25rem !important -} - -.rounded-bottom, -.rounded-left { - border-bottom-left-radius: .25rem !important -} - -.rounded-left { - border-top-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:540px) { - .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:720px) { - .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:960px) { - .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:540px) { - .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:720px) { - .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:960px) { - .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:540px) { - .float-sm-left { - float: left !important - } - - .float-sm-right { - float: right !important - } - - .float-sm-none { - float: none !important - } -} - -@media (min-width:720px) { - .float-md-left { - float: left !important - } - - .float-md-right { - float: right !important - } - - .float-md-none { - float: none !important - } -} - -@media (min-width:960px) { - .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 - } -} - -.user-select-all { - user-select: all !important -} - -.user-select-auto { - user-select: auto !important -} - -.user-select-none { - user-select: 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 { - top: 0 -} - -.fixed-bottom, -.fixed-top { - position: fixed; - right: 0; - left: 0; - z-index: 1030 -} - -.fixed-bottom { - bottom: 0 -} - -@supports (position:sticky) { - .sticky-top { - position: sticky; - top: 0; - z-index: 1020 - } -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - 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 -} - -.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:540px) { - .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:720px) { - .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:960px) { - .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 - } -} - -.stretched-link:after { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1; - pointer-events: auto; - content: ""; - background-color: transparent -} - -.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:540px) { - .text-sm-left { - text-align: left !important - } - - .text-sm-right { - text-align: right !important - } - - .text-sm-center { - text-align: center !important - } -} - -@media (min-width:720px) { - .text-md-left { - text-align: left !important - } - - .text-md-right { - text-align: right !important - } - - .text-md-center { - text-align: center !important - } -} - -@media (min-width:960px) { - .text-lg-left { - text-align: left !important - } - - .text-lg-right { - text-align: right !important - } - - .text-lg-center { - text-align: center !important - } -} - -@media (min-width:1200px) { - .text-xl-left { - text-align: left !important - } - - .text-xl-right { - text-align: right !important - } - - .text-xl-center { - text-align: center !important - } -} - -.text-lowercase { - text-transform: lowercase !important -} - -.text-uppercase { - text-transform: uppercase !important -} - -.text-capitalize { - text-transform: capitalize !important -} - -.font-weight-light { - font-weight: 300 !important -} - -.font-weight-lighter { - font-weight: lighter !important -} - -.font-weight-normal { - font-weight: 400 !important -} - -.font-weight-bold { - font-weight: 700 !important -} - -.font-weight-bolder { - font-weight: bolder !important -} - -.font-italic { - font-style: italic !important -} - -.text-white { - color: #fff !important -} - -.text-primary { - color: #007bff !important -} - -a.text-primary:focus, -a.text-primary:hover { - color: #0056b3 !important -} - -.text-secondary { - color: #6c757d !important -} - -a.text-secondary:focus, -a.text-secondary:hover { - color: #494f54 !important -} - -.text-success { - color: #28a745 !important -} - -a.text-success:focus, -a.text-success:hover { - color: #19692c !important -} - -.text-info { - color: #17a2b8 !important -} - -a.text-info:focus, -a.text-info:hover { - color: #0f6674 !important -} - -.text-warning { - color: #ffc107 !important -} - -a.text-warning:focus, -a.text-warning:hover { - color: #ba8b00 !important -} - -.text-danger { - color: #dc3545 !important -} - -a.text-danger:focus, -a.text-danger:hover { - color: #a71d2a !important -} - -.text-light { - color: #f8f9fa !important -} - -a.text-light:focus, -a.text-light:hover { - color: #cbd3da !important -} - -.text-dark { - color: #343a40 !important -} - -a.text-dark:focus, -a.text-dark:hover { - color: #121416 !important -} - -.text-body { - color: #212529 !important -} - -.text-muted { - color: #6c757d !important -} - -.text-black-50 { - color: rgba(0, 0, 0, .5) !important -} - -.text-white-50 { - color: hsla(0, 0%, 100%, .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; - word-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 - } - - blockquote, - img, - pre, - tr { - page-break-inside: avoid - } - - h2, - h3, - p { - orphans: 3; - widows: 3 - } - - h2, - h3 { - page-break-after: avoid - } - - @page { - size: a3 - } - - .container, - body { - min-width: 960px !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 - } -} - -html { - font-size: var(--pst-font-size-base); - scroll-padding-top: calc(var(--pst-header-height) + 12px) -} - -body { - padding-top: var(--pst-header-height); - background-color: #fff; - font-family: var(--pst-font-family-base); - font-weight: 400; - line-height: 1.65; - color: rgba(var(--pst-color-text-base), 1) -} - -p { - margin-bottom: 1.15rem; - font-size: 1em; - color: rgba(var(--pst-color-paragraph), 1) -} - -p.rubric { - border-bottom: 1px solid #c9c9c9 -} - -a { - color: rgba(var(--pst-color-link), 1); - text-decoration: none -} - -a:hover { - color: rgba(var(--pst-color-link-hover), 1); - text-decoration: underline -} - -a.headerlink { - color: rgba(var(--pst-color-headerlink), 1); - opacity: .4; - font-size: .8em; - padding: 0 4px; - margin-left: .2em; - text-decoration: none; - transition: all .3s ease-out; - user-select: none -} - -a.headerlink:hover { - opacity: 1 -} - -.heading-style, -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 2.75rem 0 1.05rem; - font-family: var(--pst-font-family-heading); - font-weight: 400; - line-height: 1.15 -} - -h1 { - margin-top: 0; - font-size: var(--pst-font-size-h1); - color: rgba(var(--pst-color-h1), 1) -} - -h2 { - font-size: var(--pst-font-size-h2); - color: rgba(var(--pst-color-h2), 1) -} - -h3 { - font-size: var(--pst-font-size-h3); - color: rgba(var(--pst-color-h3), 1) -} - -h4 { - font-size: var(--pst-font-size-h4); - color: rgba(var(--pst-color-h4), 1) -} - -h5 { - font-size: var(--pst-font-size-h5); - color: rgba(var(--pst-color-h5), 1) -} - -h6 { - font-size: var(--pst-font-size-h6); - color: rgba(var(--pst-color-h6), 1) -} - -.text_small, -small { - font-size: var(--pst-font-size-milli) -} - -hr { - border: 0; - border-top: 1px solid #e5e5e5 -} - -code, -kbd, -pre, -samp { - font-family: var(--pst-font-family-monospace) -} - -code { - color: rgba(var(--pst-color-inline-code), 1) -} - -pre { - margin: 1.5em 0; - padding: 10px; - background-color: rgba(var(--pst-color-preformatted-background), 1); - color: rgba(var(--pst-color-preformatted-text), 1); - line-height: 1.2em; - border: 1px solid #c9c9c9; - border-radius: .2rem; - box-shadow: 1px 1px 1px #d8d8d8 -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) minmax(0, 1fr) -} - -.navbar { - position: fixed; - min-height: var(--pst-header-height); - width: 100%; - padding: 0 -} - -.navbar .container-xl { - height: 100% -} - -@media (max-width:1199.98px) { - .navbar #navbar-start { - margin-left: 1em - } - - .navbar button.navbar-toggler { - margin-right: 1em - } -} - -@media (min-width:960px) { - .navbar #navbar-end>.navbar-end-item { - display: inline-block - } -} - -.navbar-brand { - position: relative; - height: var(--pst-header-height); - width: auto; - padding: .5rem 0; - display: flex; - align-items: center -} - -.navbar-brand p { - margin-bottom: 0 -} - -.navbar-brand img { - max-width: 100%; - height: 100%; - width: auto -} - -.navbar-light { - background: #fff !important; - box-shadow: 0 .125rem .25rem 0 rgba(0, 0, 0, .11) -} - -.navbar-light .navbar-nav li a.nav-link { - padding: 0 .5rem; - color: rgba(var(--pst-color-navbar-link), 1) -} - -.navbar-light .navbar-nav li a.nav-link:hover { - color: rgba(var(--pst-color-navbar-link-hover), 1) -} - -.navbar-light .navbar-nav>.active>.nav-link { - font-weight: 600; - color: rgba(var(--pst-color-navbar-link-active), 1) -} - -.navbar-header a { - padding: 0 15px -} - -.admonition, -div.admonition { - margin: 1.5625em auto; - padding: 0 .6rem .8rem; - overflow: hidden; - page-break-inside: avoid; - border-left: .2rem solid; - border-left-color: rgba(var(--pst-color-admonition-default), 1); - border-bottom-color: rgba(var(--pst-color-admonition-default), 1); - border-right-color: rgba(var(--pst-color-admonition-default), 1); - border-top-color: rgba(var(--pst-color-admonition-default), 1); - border-radius: .2rem; - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1); - transition: color .25s, background-color .25s, border-color .25s -} - -.admonition :last-child, -div.admonition :last-child { - margin-bottom: 0 -} - -.admonition p.admonition-title~*, -div.admonition p.admonition-title~* { - margin-left: 1.4rem; - margin-right: 1.4rem -} - -.admonition>ol, -.admonition>ul, -div.admonition>ol, -div.admonition>ul { - margin-left: 1em -} - -.admonition>.admonition-title, -div.admonition>.admonition-title { - position: relative; - margin: 0 -.6rem; - padding: .4rem .6rem .4rem 2rem; - font-weight: 700; - background-color: rgba(var(--pst-color-admonition-default), .1) -} - -.admonition>.admonition-title:before, -div.admonition>.admonition-title:before { - position: absolute; - left: .6rem; - width: 1rem; - height: 1rem; - color: rgba(var(--pst-color-admonition-default), 1); - font-family: Font Awesome\ 5 Free; - font-weight: 900; - content: var(--pst-icon-admonition-default) -} - -.admonition>.admonition-title+*, -div.admonition>.admonition-title+* { - margin-top: .4em -} - -.admonition.attention, -div.admonition.attention { - border-color: rgba(var(--pst-color-admonition-attention), 1) -} - -.admonition.attention>.admonition-title, -div.admonition.attention>.admonition-title { - background-color: rgba(var(--pst-color-admonition-attention), .1) -} - -.admonition.attention>.admonition-title:before, -div.admonition.attention>.admonition-title:before { - color: rgba(var(--pst-color-admonition-attention), 1); - content: var(--pst-icon-admonition-attention) -} - -.admonition.caution, -div.admonition.caution { - border-color: rgba(var(--pst-color-admonition-caution), 1) -} - -.admonition.caution>.admonition-title, -div.admonition.caution>.admonition-title { - background-color: rgba(var(--pst-color-admonition-caution), .1) -} - -.admonition.caution>.admonition-title:before, -div.admonition.caution>.admonition-title:before { - color: rgba(var(--pst-color-admonition-caution), 1); - content: var(--pst-icon-admonition-caution) -} - -.admonition.warning, -div.admonition.warning { - border-color: rgba(var(--pst-color-admonition-warning), 1) -} - -.admonition.warning>.admonition-title, -div.admonition.warning>.admonition-title { - background-color: rgba(var(--pst-color-admonition-warning), .1) -} - -.admonition.warning>.admonition-title:before, -div.admonition.warning>.admonition-title:before { - color: rgba(var(--pst-color-admonition-warning), 1); - content: var(--pst-icon-admonition-warning) -} - -.admonition.danger, -div.admonition.danger { - border-color: rgba(var(--pst-color-admonition-danger), 1) -} - -.admonition.danger>.admonition-title, -div.admonition.danger>.admonition-title { - background-color: rgba(var(--pst-color-admonition-danger), .1) -} - -.admonition.danger>.admonition-title:before, -div.admonition.danger>.admonition-title:before { - color: rgba(var(--pst-color-admonition-danger), 1); - content: var(--pst-icon-admonition-danger) -} - -.admonition.error, -div.admonition.error { - border-color: rgba(var(--pst-color-admonition-error), 1) -} - -.admonition.error>.admonition-title, -div.admonition.error>.admonition-title { - background-color: rgba(var(--pst-color-admonition-error), .1) -} - -.admonition.error>.admonition-title:before, -div.admonition.error>.admonition-title:before { - color: rgba(var(--pst-color-admonition-error), 1); - content: var(--pst-icon-admonition-error) -} - -.admonition.hint, -div.admonition.hint { - border-color: rgba(var(--pst-color-admonition-hint), 1) -} - -.admonition.hint>.admonition-title, -div.admonition.hint>.admonition-title { - background-color: rgba(var(--pst-color-admonition-hint), .1) -} - -.admonition.hint>.admonition-title:before, -div.admonition.hint>.admonition-title:before { - color: rgba(var(--pst-color-admonition-hint), 1); - content: var(--pst-icon-admonition-hint) -} - -.admonition.tip, -div.admonition.tip { - border-color: rgba(var(--pst-color-admonition-tip), 1) -} - -.admonition.tip>.admonition-title, -div.admonition.tip>.admonition-title { - background-color: rgba(var(--pst-color-admonition-tip), .1) -} - -.admonition.tip>.admonition-title:before, -div.admonition.tip>.admonition-title:before { - color: rgba(var(--pst-color-admonition-tip), 1); - content: var(--pst-icon-admonition-tip) -} - -.admonition.important, -div.admonition.important { - border-color: rgba(var(--pst-color-admonition-important), 1) -} - -.admonition.important>.admonition-title, -div.admonition.important>.admonition-title { - background-color: rgba(var(--pst-color-admonition-important), .1) -} - -.admonition.important>.admonition-title:before, -div.admonition.important>.admonition-title:before { - color: rgba(var(--pst-color-admonition-important), 1); - content: var(--pst-icon-admonition-important) -} - -.admonition.note, -div.admonition.note { - border-color: rgba(var(--pst-color-admonition-note), 1) -} - -.admonition.note>.admonition-title, -div.admonition.note>.admonition-title { - background-color: rgba(var(--pst-color-admonition-note), .1) -} - -.admonition.note>.admonition-title:before, -div.admonition.note>.admonition-title:before { - color: rgba(var(--pst-color-admonition-note), 1); - content: var(--pst-icon-admonition-note) -} - -table.field-list { - border-collapse: separate; - border-spacing: 10px; - margin-left: 1px -} - -table.field-list th.field-name { - padding: 1px 8px 1px 5px; - white-space: nowrap; - background-color: #eee -} - -table.field-list td.field-body p { - font-style: italic -} - -table.field-list td.field-body p>strong { - font-style: normal -} - -table.field-list td.field-body blockquote { - border-left: none; - margin: 0 0 .3em; - padding-left: 30px -} - -.table.autosummary td:first-child { - white-space: nowrap -} - -.sig { - font-family: var(--pst-font-family-monospace) -} - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset -} - -.sig.c .k, -.sig.c .kt, -.sig.c .m, -.sig.c .s, -.sig.c .sc, -.sig.cpp .k, -.sig.cpp .kt, -.sig.cpp .m, -.sig.cpp .s, -.sig.cpp .sc { - color: rgba(var(--pst-color-text-base), 1) -} - -.sig-name { - color: rgba(var(--pst-color-inline-code), 1) -} - -td.text-align\:left, -th.text-align\:left { - text-align: left -} - -td.text-align\:right, -th.text-align\:right { - text-align: right -} - -td.text-align\:center, -th.text-align\:center { - text-align: center -} - -div.deprecated, -div.versionadded, -div.versionchanged { - vertical-align: middle; - margin: 1.5625em auto; - padding: 0 .6rem; - overflow: hidden; - page-break-inside: avoid; - border-left: .2rem solid; - border-left-color: rgba(var(--pst-color-versionmodified-default), 1); - border-bottom-color: rgba(var(--pst-color-versionmodified-default), 1); - border-right-color: rgba(var(--pst-color-versionmodified-default), 1); - border-top-color: rgba(var(--pst-color-versionmodified-default), 1); - border-radius: .2rem; - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1); - transition: color .25s, background-color .25s, border-color .25s; - background-color: rgba(var(--pst-color-admonition-default), .1) -} - -div.deprecated>p, -div.versionadded>p, -div.versionchanged>p { - margin-bottom: .6rem; - margin-top: .6rem -} - -div.versionadded { - border-color: rgba(var(--pst-color-versionmodified-added), 1); - background-color: rgba(var(--pst-color-versionmodified-added), .1) -} - -div.versionchanged { - border-color: rgba(var(--pst-color-versionmodified-changed), 1); - background-color: rgba(var(--pst-color-versionmodified-changed), .1) -} - -div.deprecated { - border-color: rgba(var(--pst-color-versionmodified-deprecated), 1); - background-color: rgba(var(--pst-color-versionmodified-deprecated), .1) -} - -span.versionmodified { - font-weight: 700 -} - -span.versionmodified:before { - font-style: normal; - margin-right: .6rem; - color: rgba(var(--pst-color-versionmodified-default), 1); - font-family: Font Awesome\ 5 Free; - font-weight: 900; - content: var(--pst-icon-versionmodified-default) -} - -span.versionmodified.added:before { - color: rgba(var(--pst-color-versionmodified-added), 1); - content: var(--pst-icon-versionmodified-added) -} - -span.versionmodified.changed:before { - color: rgba(var(--pst-color-versionmodified-changed), 1); - content: var(--pst-icon-versionmodified-changed) -} - -span.versionmodified.deprecated:before { - color: rgba(var(--pst-color-versionmodified-deprecated), 1); - content: var(--pst-icon-versionmodified-deprecated) -} - -blockquote { - padding: 0 1em; - color: #6a737d; - border-left: .25em solid #dfe2e5 -} - -dt.label>span.brackets:not(:only-child):before { - content: "[" -} - -dt.label>span.brackets:not(:only-child):after { - content: "]" -} - -a.footnote-reference { - vertical-align: super; - font-size: small -} - -.topic { - background-color: #eee -} - -.seealso dd { - margin-top: 0; - margin-bottom: 0 -} - -.viewcode-back { - font-family: var(--pst-font-family-base) -} - -.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9 -} - -span.guilabel { - border: 1px solid #7fbbe3; - background: #e7f2fa; - font-size: 80%; - font-weight: 700; - border-radius: 4px; - padding: 2.4px 6px; - margin: auto 2px -} - -footer { - width: 100%; - border-top: 1px solid #ccc; - padding: 10px -} - -footer .footer-item p { - margin-bottom: 0 -} - -.bd-search { - position: relative; - padding: 1rem 15px; - margin-right: -15px; - margin-left: -15px -} - -.bd-search .icon { - position: absolute; - color: #a4a6a7; - left: 25px -} - -.bd-search input { - border-radius: .2rem; - border: 1px solid #e5e5e5; - padding-left: 35px -} - -.bd-toc { - -ms-flex-order: 2; - order: 2; - height: calc(100vh - 2rem); - overflow-y: auto -} - -@supports (position:-webkit-sticky) or (position:sticky) { - .bd-toc { - position: -webkit-sticky; - position: sticky; - top: var(--pst-header-height); - height: calc(100vh - 5rem); - overflow-y: auto - } -} - -.bd-toc .onthispage { - color: #a4a6a7 -} - -.section-nav { - padding-left: 0; - border-left: 1px solid #eee; - border-bottom: none -} - -.section-nav ul { - padding-left: 1rem -} - -.toc-entry, -.toc-entry a { - display: block -} - -.toc-entry a { - padding: .125rem 1.5rem; - color: rgba(var(--pst-color-toc-link), 1) -} - -@media (min-width:1200px) { - .toc-entry a { - padding-right: 0 - } -} - -.toc-entry a:hover { - color: rgba(var(--pst-color-toc-link-hover), 1); - text-decoration: none -} - -.bd-links { - padding-top: 1rem; - padding-bottom: 1rem; - margin-right: -15px; - margin-left: -15px -} - -@media (min-width:720px) { - .bd-links { - display: block - } -} - -.bd-sidenav { - display: none -} - -.bd-content { - padding-top: 20px -} - -.bd-content .section { - max-width: 100% -} - -.bd-content .section table { - display: block; - overflow: auto -} - -.bd-toc-link { - display: block; - padding: .25rem 1.5rem; - font-weight: 600; - color: rgba(0, 0, 0, .65) -} - -.bd-toc-link:hover { - color: rgba(0, 0, 0, .85); - text-decoration: none -} - -.bd-toc-item.active { - margin-bottom: 1rem -} - -.bd-toc-item.active:not(:first-child) { - margin-top: 1rem -} - -.bd-toc-item.active>.bd-toc-link { - color: rgba(0, 0, 0, .85) -} - -.bd-toc-item.active>.bd-toc-link:hover { - background-color: transparent -} - -.bd-toc-item.active>.bd-sidenav { - display: block -} - -nav.bd-links p.caption { - font-size: var(--pst-sidebar-caption-font-size); - text-transform: uppercase; - font-weight: 700; - position: relative; - margin-top: 1.25em; - margin-bottom: .5em; - padding: 0 1.5rem; - color: rgba(var(--pst-color-sidebar-caption), 1) -} - -nav.bd-links p.caption:first-child { - margin-top: 0 -} - -.bd-sidebar .nav { - font-size: var(--pst-sidebar-font-size) -} - -.bd-sidebar .nav ul { - list-style: none; - padding: 0 0 0 1.5rem -} - -.bd-sidebar .nav li>a { - display: block; - padding: .25rem 1.5rem; - color: rgba(var(--pst-color-sidebar-link), 1) -} - -.bd-sidebar .nav li>a:hover { - color: rgba(var(--pst-color-sidebar-link-hover), 1); - text-decoration: none; - background-color: transparent -} - -.bd-sidebar .nav li>a.reference.external:after { - font-family: Font Awesome\ 5 Free; - font-weight: 900; - content: "\f35d"; - font-size: .75em; - margin-left: .3em -} - -.bd-sidebar .nav .active:hover>a, -.bd-sidebar .nav .active>a { - font-weight: 600; - color: rgba(var(--pst-color-sidebar-link-active), 1) -} - -.toc-h2 { - font-size: .85rem -} - -.toc-h3 { - font-size: .75rem -} - -.toc-h4 { - font-size: .65rem -} - -.toc-entry>.nav-link.active { - font-weight: 600; - color: #130654; - color: rgba(var(--pst-color-toc-link-active), 1); - background-color: transparent; - border-left: 2px solid rgba(var(--pst-color-toc-link-active), 1) -} - -.nav-link:hover { - border-style: none -} - -#navbar-main-elements li.nav-item i { - font-size: .7rem; - padding-left: 2px; - vertical-align: middle -} - -.bd-toc .nav .nav, -.list-caption .nav { - display: none -} - -.bd-toc .nav .nav.visible, -.bd-toc .nav>.active>ul, -.list-caption .nav.visible, -.list-caption>.active>ul { - display: block -} - -.prev-next-area { - margin: 20px 0 -} - -.prev-next-area p { - margin: 0 .3em; - line-height: 1.3em -} - -.prev-next-area i { - font-size: 1.2em -} - -.prev-next-area a { - display: flex; - align-items: center; - border: none; - padding: 10px; - max-width: 45%; - overflow-x: hidden; - color: rgba(0, 0, 0, .65); - text-decoration: none -} - -.prev-next-area a p.prev-next-title { - color: rgba(var(--pst-color-link), 1); - font-weight: 600; - font-size: 1.1em -} - -.prev-next-area a:hover p.prev-next-title { - text-decoration: underline -} - -.prev-next-area a .prev-next-info { - flex-direction: column; - margin: 0 .5em -} - -.prev-next-area a .prev-next-info .prev-next-subtitle { - text-transform: capitalize -} - -.prev-next-area a.left-prev { - float: left -} - -.prev-next-area a.right-next { - float: right -} - -.prev-next-area a.right-next div.prev-next-info { - text-align: right -} - -.alert { - padding-bottom: 0 -} - -.alert-info a { - color: #e83e8c -} - -#navbar-icon-links i.fa, -#navbar-icon-links i.fab, -#navbar-icon-links i.far, -#navbar-icon-links i.fas { - vertical-align: middle; - font-style: normal; - font-size: 1.5rem; - line-height: 1.25 -} - -#navbar-icon-links i.fa-github-square:before { - color: #333 -} - -#navbar-icon-links i.fa-twitter-square:before { - color: #55acee -} - -#navbar-icon-links i.fa-gitlab:before { - color: #548 -} - -#navbar-icon-links i.fa-bitbucket:before { - color: #0052cc -} - -#navbar-icon-links img.icon-link-image { - height: 1.5em -} - -.tocsection { - border-left: 1px solid #eee; - padding: .3rem 1.5rem -} - -.tocsection i { - padding-right: .5rem -} - -.editthispage { - padding-top: 2rem -} - -.editthispage a { - color: var(--pst-color-sidebar-link-active) -} - -.xr-wrap[hidden] { - display: block !important -} - -.toctree-checkbox { - position: absolute; - display: none -} - -.toctree-checkbox~ul { - display: none -} - -.toctree-checkbox~label i { - transform: rotate(0deg) -} - -.toctree-checkbox:checked~ul { - display: block -} - -.toctree-checkbox:checked~label i { - transform: rotate(180deg) -} - -.bd-sidebar { - padding-top: 1em; - overflow-y: auto; - display: flex; - flex-direction: column -} - -@media (min-width:720px) { - .bd-sidebar { - border-right: 1px solid rgba(0, 0, 0, .1) - } - - @supports (position:-webkit-sticky) or (position:sticky) { - .bd-sidebar { - position: -webkit-sticky; - position: sticky; - top: var(--pst-header-height); - z-index: 1000; - height: calc(100vh - var(--pst-header-height)) - } - } -} - -.bd-sidebar.no-sidebar { - border-right: 0 -} - -.bd-sidebar .sidebar-end-items { - margin-top: auto; - margin-bottom: 1em -} - -.bd-sidebar .list-caption { - list-style: none; - padding-left: 0 -} - -.bd-sidebar li { - position: relative -} - -.bd-sidebar li.has-children>.reference { - padding-right: 30px -} - -.bd-sidebar label { - position: absolute; - top: 0; - right: 0; - height: 30px; - width: 30px; - cursor: pointer; - display: flex; - justify-content: center; - align-items: center -} - -.bd-sidebar label:hover { - background: rgba(var(--pst-color-sidebar-expander-background-hover), 1) -} - -.bd-sidebar label i { - display: inline-block; - font-size: .75rem; - text-align: center -} - -.bd-sidebar label i:hover { - color: rgba(var(--pst-color-sidebar-link-hover), 1) -} - -.bd-sidebar .label-parts { - width: 100%; - height: 100% -} - -.bd-sidebar .label-parts:hover { - background: none -} - -.bd-sidebar .label-parts i { - width: 30px; - position: absolute; - top: .3em; - right: 0 -} - -div.doctest>div.highlight span.gp, -span.linenos, -table.highlighttable td.linenos { - user-select: none; - -webkit-user-select: text; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none -} - -.docutils.container { - padding-left: unset; - padding-right: unset -} \ No newline at end of file diff --git a/doc/rst/_css_helpers/sphinx-book-theme-0.3.3.css b/doc/rst/_css_helpers/sphinx-book-theme-0.3.3.css deleted file mode 100644 index e9c4c25671..0000000000 --- a/doc/rst/_css_helpers/sphinx-book-theme-0.3.3.css +++ /dev/null @@ -1,1425 +0,0 @@ -/*! sphinx-book-theme CSS - * BSD 3-Clause License - * Copyright (c) 2020, EBP - * All rights reserved. - * - * This follows the 7-1 pattern described here: - * https://sass-guidelin.es/#architecture - */ -:root { - --pst-font-size-base: none; - --pst-color-primary: rgb(87, 154, 202); - --pst-color-admonition-note: var(--pst-color-primary); - --pst-color-admonition-default: var(--pst-color-primary); - --pst-color-info: rgb(255, 193, 7); - --pst-color-admonition-tip: var(--pst-color-info); - --pst-color-admonition-hint: var(--pst-color-info); - --pst-color-admonition-important: var(--pst-color-info); - --pst-color-warning: rgb(245, 162, 82); - --pst-color-danger: rgb(230, 101, 129); - --pst-color-admonition-warning: var(--pst-color-danger); - --pst-color-link: rgb(0, 113, 188); - --sbt-font-size-regular: 100%; - --sbt-font-size-large: 112.5%; - --sbt-font-size-small-1: 87.5%; - --sbt-font-size-small-2: 70%; - --sbt-sidebar-font-size: var(--sbt-font-size-small-1); - --sbt-header-article-font-size: var(--sbt-font-size-small-1); - --sbt-prevnext-font-size: var(--sbt-font-size-small-1); - --sbt-footer-font-size: var(--sbt-font-size-small-1) -} - -.sbt-scroll-pixel-helper { - position: absolute; - width: 0; - height: 0; - top: 0; - left: 0 -} - -.visually-hidden { - clip: rect(0, 0, 0, 0) !important; - border: 0 !important; - height: 1px !important; - margin: -1px !important; - overflow: hidden !important; - padding: 0 !important; - position: absolute !important; - white-space: nowrap !important; - width: 1px !important -} - -.d-n, -.onlyprint { - display: none -} - -@media print { - .onlyprint { - display: block !important - } -} - -@media print { - .noprint { - display: none !important - } -} - -.col { - min-width: 0 -} - -.content-container a.headerlink { - opacity: 0; - margin-left: .2em -} - -.content-container a.headerlink:hover { - background-color: transparent; - color: rgba(var(--pst-color-link), 1); - opacity: 1 !important -} - -.content-container a, -.content-container a:visited { - color: rgba(var(--pst-color-link), 1) -} - -.content-container h1, -.content-container h2, -.content-container h3, -.content-container h4, -.content-container h5 { - color: #000 -} - -.content-container h1:hover a.headerlink, -.content-container h2:hover a.headerlink, -.content-container h3:hover a.headerlink, -.content-container h4:hover a.headerlink, -.content-container h5:hover a.headerlink { - opacity: .5 -} - -.content-container h1 a.toc-backref, -.content-container h2 a.toc-backref, -.content-container h3 a.toc-backref, -.content-container h4 a.toc-backref, -.content-container h5 a.toc-backref { - color: inherit -} - -.content-container h3, -.content-container h4, -.content-container h5, -.content-container h6 { - margin-top: 1em -} - -.content-container ol p, -.content-container ul p { - margin-bottom: 0 -} - -.content-container p.centered { - text-align: center -} - -.content-container .footnote-reference, -.content-container a.bibtex.internal { - font-size: 1em -} - -@media print { - #jb-print-docs-body { - max-width: 90%; - margin: auto - } - - #jb-print-docs-body h1 { - font-size: 3em; - text-align: center; - margin-bottom: 0 - } - - #main-content { - max-width: 67% !important; - margin-left: 5% !important; - padding-top: 0 - } - - #main-content h1:first-of-type { - display: none - } - - .container { - min-width: 0 !important - } - - h1 { - margin-top: 1em; - margin-bottom: 1em - } - - h1, - h2, - h3, - h4 { - break-after: avoid; - color: #000 - } - - table { - break-inside: avoid - } - - pre { - word-wrap: break-word - } - - a.headerlink { - display: none - } - - blockquote.epigraph { - border: none - } - - .footer { - margin-top: 1em - } -} - -body { - padding-top: 0 !important -} - -#main-content, -#print-main-content { - transition: padding .25s ease-out; - padding-top: 1.5em -} - -@media (min-width:768px) { - #main-content { - max-width: 70% - } -} - -footer.footer-article { - border-top: none; - padding: 0 -} - -footer.footer-article .prev-next-area { - font-size: var(--sbt-prevnext-font-size) -} - -footer.footer-article .prev-next-area a { - margin-bottom: 1em; - padding-left: 0; - padding-right: 0 -} - -@media (min-width:768px) { - footer.footer-article .prev-next-area { - max-width: 70% - } -} - -footer { - font-size: var(--sbt-font-size-small-1) -} - -.header-article { - height: 3em; - background-color: #fff; - transition: left .2s; - font-size: var(--sbt-header-article-font-size) -} - -@media (max-width:768px) { - .header-article { - height: 3.75em - } -} - -.scrolled .header-article { - box-shadow: 0 6px 6px -6px rgba(0, 0, 0, .3) -} - -.header-article .header-article-main { - height: 3em -} - -@media (max-width:768px) { - .header-article .header-article-main { - height: 3.75em - } -} - -.header-article .header-article-main .header-article__left, -.header-article .header-article-main .header-article__right { - display: flex; - align-items: center -} - -.header-article .header-article-main .header-article__right { - margin-left: auto -} - -.header-item { - width: 100%; - text-align: center -} - -.header-item:empty { - display: none -} - -.header-item.announcement { - background-color: #616161; - color: #fff; - padding: .4em 12.5% -} - -@media (max-width:768px) { - .header-item.announcement { - padding: .4em 2% - } -} - -#site-navigation { - padding-top: 0; - width: 275px; - font-size: var(--sbt-sidebar-font-size); - top: 0 !important; - background: #fff; - border-right: 1px solid rgba(0, 0, 0, .1); - transition: margin-left .25s ease 0s, opacity .25s ease 0s, visibility .25s ease 0s; - overflow-y: unset; - height: 100vh -} - -@media (max-width:768px) { - #site-navigation { - height: 100%; - position: fixed; - width: 75%; - max-width: 300px; - font-size: 1.2em; - z-index: 1100 - } -} - -#site-navigation .bd-sidebar__content { - overflow-y: auto; - flex-grow: 1; - display: flex; - flex-direction: column -} - -#site-navigation .bd-sidebar__content::-webkit-scrollbar { - width: .3rem; - height: .3rem -} - -#site-navigation .bd-sidebar__content::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: .25rem -} - -#site-navigation .bd-sidebar__content::-webkit-scrollbar-thumb:hover { - background: #a0a0a0 -} - -#site-navigation .bd-sidebar__content:not(:hover)::-webkit-scrollbar-thumb { - visibility: hidden -} - -#site-navigation .bd-sidebar__bottom, -#site-navigation .bd-sidebar__top { - padding: 0 1rem 0 1.5rem -} - -#site-navigation .bd-sidebar__bottom { - margin-top: auto; - margin-bottom: 2em -} - -#site-navigation nav ul.nav li a, -#site-navigation nav ul.nav ul li a { - color: #5a5a5a -} - -#site-navigation nav ul.nav a:hover, -#site-navigation nav ul.nav li.active>a, -#site-navigation nav ul.nav li.active>a:hover { - color: rgba(var(--pst-color-link), 1) -} - -#site-navigation nav ul.nav ul { - padding-left: 1rem -} - -#site-navigation h1.site-logo { - margin: .5em 0 0; - font-size: 1.1em; - color: #000; - text-align: center -} - -#site-navigation div.navbar_extra_footer { - text-align: center; - font-size: .9em; - color: #5a5a5a; - margin-bottom: 3em -} - -#site-navigation.single-page { - border-right: 0 -} - -@media (min-width:768px) { - div.navbar-brand-box { - padding-top: 2em - } -} - -div.navbar-brand-box a.navbar-brand { - width: 100%; - height: auto; - flex-direction: column -} - -div.navbar-brand-box a.navbar-brand img { - display: block; - height: auto; - width: auto; - max-height: 10vh; - max-width: 100%; - margin: 0 auto -} - -@media (min-width:768px) { - div.navbar-brand-box a.navbar-brand img { - max-height: 15vh !important - } -} - -nav.bd-links { - margin-left: 0; - overflow-y: visible; - max-height: none -} - -nav.bd-links .toctree-l1 a, -nav.bd-links p.caption { - padding-left: 0 -} - -.bd-toc { - padding: 0 !important; - right: -1em; - height: auto; - transition: margin-right .25s ease 0s, opacity .25s ease 0s, visibility .25s ease 0s -} - -.bd-toc .toc-entry a, -.bd-toc div.onthispage { - color: #5a5a5a -} - -@media (max-width:768px) { - .bd-toc { - z-index: 1100; - top: 0; - right: 0; - position: fixed; - height: 100%; - width: 75%; - max-width: 300px; - background-color: #fff; - border-left: 1px solid rgba(0, 0, 0, .1); - font-size: 1.4em - } - - .bd-toc li { - font-size: .8em - } -} - -.bd-toc nav { - opacity: 0; - max-height: 0; - transition: opacity .2s ease, max-height .7s ease; - overflow-y: hidden; - background: #fff -} - -.bd-toc nav::-webkit-scrollbar { - width: .3rem; - height: .3rem -} - -.bd-toc nav::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: .25rem -} - -.bd-toc nav::-webkit-scrollbar-thumb:hover { - background: #a0a0a0 -} - -.bd-toc nav:not(:hover)::-webkit-scrollbar-thumb { - visibility: hidden -} - -.bd-toc nav a:hover, -.bd-toc nav li.active>a.active { - color: rgba(var(--pst-color-link), 1) -} - -.bd-toc nav li.active>a.active { - border-left: 2px solid rgba(var(--pst-color-link), 1) -} - -.bd-toc nav>.nav { - border-left: 1px solid #eee -} - -.bd-toc nav>.nav .nav { - border-left: none -} - -.bd-toc.show nav, -.bd-toc:hover nav { - max-height: 90vh; - opacity: 1; - overflow-y: auto -} - -.bd-toc.show .tocsection:after, -.bd-toc:hover .tocsection:after { - opacity: 0 -} - -@media (max-width:768px) { - .bd-toc nav { - max-height: 90vh; - opacity: 1; - overflow-y: auto - } - - .bd-toc .tocsection:after { - opacity: 0 - } -} - -.bd-toc .tocsection { - padding: .5rem 0 .5rem 1rem !important -} - -.bd-toc .tocsection:after { - content: "\f107"; - font-family: Font Awesome\ 5 Free; - font-weight: 900; - padding-left: .5em; - transition: opacity .3s ease -} - -.bd-toc .toc-entry a { - padding: .125rem 1rem !important -} - -.bd-toc div.editthispage { - display: none -} - -input.sidebar-toggle { - display: none; - position: absolute -} - -@media (min-width:768px) { - input#__navigation:checked~.container-xl #site-navigation { - visibility: hidden; - opacity: 0; - margin-left: -275px - } - - input#__navigation:checked~.container-xl #main-content { - padding-left: 4rem; - padding-right: 4rem - } -} - -@media (max-width:768px) { - input#__navigation:not(:checked)~.container-xl #site-navigation { - visibility: hidden; - opacity: 0; - margin-left: -75% - } -} - -@media (max-width:768px) { - input#__page-toc:not(:checked)~.container-xl .bd-toc { - visibility: hidden; - opacity: 0; - margin-right: -75% - } -} - -label.overlay { - height: 0; - opacity: 0; - position: fixed; - top: 0; - transition: width 0ms, height 0ms, opacity .25s ease-out; - width: 0 -} - -label.overlay.overlay-navbar { - background-color: rgba(0, 0, 0, .54) -} - -@media (max-width:768px) { - input:checked+label.overlay { - height: 100%; - opacity: 1; - width: 100% - } - - input:checked+label.overlay.overlay-navbar { - z-index: 1099 - } - - input:checked+label.overlay.overlay-pagetoc { - z-index: 1019 - } -} - -.headerbtn { - justify-content: center; - background-color: #fff; - color: #5a5a5a; - cursor: pointer; - border: none; - padding: .1rem .5rem; - margin: 0 .1rem -} - -.headerbtn, -.headerbtn span { - display: flex; - align-items: center -} - -.headerbtn i, -.headerbtn img { - margin: auto; - width: 1em; - text-align: center; - font-size: 1.5em -} - -.menu-dropdown__content:hover, -.menu-dropdown__trigger:hover+.menu-dropdown__content { - visibility: visible; - opacity: 1 -} - -.menu-dropdown__content { - position: absolute; - visibility: hidden; - opacity: 0; - transform: translateX(-75%); - transition: opacity .2s ease-out; - width: 10rem; - border-radius: .4em; - box-shadow: 0 3px 10px 0 rgba(0, 0, 0, .25); - padding: .5em; - background-color: #fff -} - -.menu-dropdown__content .headerbtn { - justify-content: left; - padding: .1rem 0 -} - -.menu-dropdown__content ul { - list-style: none; - padding-left: 0; - margin-bottom: 0 -} - -.menu-dropdown__content span { - display: flex -} - -.menu-dropdown__content span.headerbtn__icon-container { - width: 2em -} - -.menu-dropdown__content span.headerbtn__text-container { - flex-grow: 1; - margin-left: .5em -} - -.menu-dropdown__content i, -.menu-dropdown__content img { - font-size: 1.2em -} - -div.header-article-main .header-article__left a, -div.header-article-main .header-article__left button, -div.header-article-main .header-article__left label, -div.header-article-main .header-article__right a, -div.header-article-main .header-article__right button, -div.header-article-main .header-article__right label { - color: #5a5a5a -} - -div.header-article-main .header-article__left a:focus, -div.header-article-main .header-article__left a:hover, -div.header-article-main .header-article__left button:focus, -div.header-article-main .header-article__left button:hover, -div.header-article-main .header-article__left label:focus, -div.header-article-main .header-article__left label:hover, -div.header-article-main .header-article__right a:focus, -div.header-article-main .header-article__right a:hover, -div.header-article-main .header-article__right button:focus, -div.header-article-main .header-article__right button:hover, -div.header-article-main .header-article__right label:focus, -div.header-article-main .header-article__right label:hover { - color: #000; - box-shadow: none; - text-decoration: none -} - -.headerbtn-page-toc { - display: block -} - -@media (min-width:768px) { - .headerbtn-page-toc { - display: none - } -} - -dt:target, -span.highlighted { - background-color: rgba(243, 119, 38, .25882352941176473) -} - -.admonition { - border-radius: .4em; - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1) -} - -.admonition.seealso { - border-color: #28a745 -} - -.admonition.seealso .admonition-title { - background-color: rgba(40, 167, 70, .1) -} - -.admonition.seealso .admonition-title:before { - color: #28a745; - content: "\f064" -} - -code { - font-size: 87.5% !important -} - -pre { - border-radius: .4em -} - -pre::-webkit-scrollbar { - width: .3rem; - height: .3rem -} - -pre::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: .25rem -} - -pre::-webkit-scrollbar-thumb:hover { - background: #a0a0a0 -} - -div[class*=highlight-], -pre { - clear: none -} - -.highlighttable .linenos { - vertical-align: baseline -} - -div.highlight { - background: none; - margin-bottom: 1em -} - -.cm-s-default { - font-family: var(--jp-code-font-family); - font-size: var(--jp-code-font-size); - line-height: var(--jp-code-line-height) -} - -.CodeMirror-focused { - background-color: var(--jp-cell-editor-active-background) !important; - border: var(--jp-border-width) solid var(--jp-cell-editor-active-border-color); - margin: -1px -} - -dl.field-list dd, -dl.simple dd { - margin-left: 1.5em -} - -dl.footnote span.fn-backref { - font-size: 1em; - padding-left: .1em -} - -dl.footnote dd { - font-size: .9em; - margin-left: 3em -} - -.footnote-reference, -a.bibtex.internal { - font-size: 1em -} - -dl.glossary dd { - margin-left: 1.5em -} - -img { - max-width: 100% -} - -img.align-center { - margin-left: auto; - margin-right: auto; - display: block -} - -img.align-left { - clear: left; - float: left; - margin-right: 1em -} - -img.align-right { - clear: right; - float: right; - margin-left: 1em -} - -div.figure { - width: 100%; - margin-bottom: 1em; - text-align: center -} - -div.figure.align-left { - text-align: left -} - -div.figure.align-left p.caption { - margin-left: 0 -} - -div.figure.align-right { - text-align: right -} - -div.figure.align-right p.caption { - margin-right: 0 -} - -div.figure p.caption { - margin: .5em 10% -} - -div.figure.margin-caption p.caption, -div.figure.margin p.caption { - margin: .5em 0 -} - -div.figure.margin-caption p.caption { - text-align: left -} - -div.figure span.caption-number { - font-weight: 700 -} - -div.figure span { - font-size: .9rem -} - -label.margin-toggle { - margin-bottom: 0 -} - -label.margin-toggle.marginnote-label { - display: none -} - -label.margin-toggle sup { - user-select: none -} - -@media (max-width:768px) { - label.margin-toggle { - cursor: pointer; - color: #0071bc - } - - label.margin-toggle.marginnote-label { - display: inline - } - - label.margin-toggle.marginnote-label:after { - content: "\2295" - } -} - -input.margin-toggle { - display: none -} - -@media (max-width:768px) { - - input.margin-toggle:checked+.marginnote, - input.margin-toggle:checked+.sidenote { - display: block; - float: left; - left: 1rem; - clear: both; - width: 95%; - margin: 1rem 2.5%; - position: relative - } -} - -span.marginnote, -span.sidenote { - width: 40%; - float: right; - background-color: unset; - font-size: .9em; - border-left: none -} - -span.marginnote sup, -span.sidenote sup { - user-select: none -} - -@media (min-width:768px) { - - span.marginnote, - span.sidenote { - border: none; - width: 39.85714%; - margin: 0 -42.85714% 0 0; - clear: right - } - - span.marginnote p.sidebar-title, - span.sidenote p.sidebar-title { - margin-bottom: .1em - } -} - -@media (max-width:768px) { - - span.marginnote, - span.sidenote { - display: none - } -} - -.cell.tag_margin, -.cell.tag_popout, -aside.margin, -div.margin, -figure.margin { - width: 40%; - float: right; - background-color: unset; - border-left: 1px solid #a4a6a7; - font-size: .9em -} - -@media (min-width:768px) { - - .cell.tag_margin, - .cell.tag_popout, - aside.margin, - div.margin, - figure.margin { - border: none; - width: 39.85714%; - margin: 0 -42.85714% 0 0; - clear: right - } - - .cell.tag_margin p.sidebar-title, - .cell.tag_popout p.sidebar-title, - aside.margin p.sidebar-title, - div.margin p.sidebar-title, - figure.margin p.sidebar-title { - margin-bottom: .1em - } -} - -.cell.tag_margin div.cell.tag_margin .cell_output, -.cell.tag_popout div.cell.tag_margin .cell_output, -aside.margin div.cell.tag_margin .cell_output, -div.margin div.cell.tag_margin .cell_output, -figure.margin div.cell.tag_margin .cell_output { - padding-left: 0 -} - -div.figure.margin-caption figcaption, -div.figure.margin-caption p.caption, -figure.margin-caption figcaption { - width: 40%; - float: right; - background-color: unset; - border-left: 1px solid #a4a6a7; - font-size: .9em -} - -@media (min-width:768px) { - - div.figure.margin-caption figcaption, - div.figure.margin-caption p.caption, - figure.margin-caption figcaption { - border: none; - width: 39.85714%; - margin: 0 -42.85714% 0 0; - clear: right - } - - div.figure.margin-caption figcaption p.sidebar-title, - div.figure.margin-caption p.caption p.sidebar-title, - figure.margin-caption figcaption p.sidebar-title { - margin-bottom: .1em - } -} - -@media (min-width:768px) { - - .full-width, - .full_width, - div.cell.tag_full-width, - div.cell.tag_full_width { - max-width: 142.85714%; - width: 142.85714% - } -} - -.margin-caption figcaption { - text-align: left -} - -div.math { - position: relative; - display: flex; - flex-direction: row-reverse; - align-items: center -} - -div.math .headerlink { - font-size: 1em; - padding: 0 .2em; - margin-left: 0 -} - -div.math .headerlink:hover { - opacity: 1 -} - -div.math:hover .headerlink { - opacity: .5 -} - -span.eqno { - font-size: 1.2em; - margin-left: .5em -} - -.MathJax { - overflow-x: auto; - margin-right: auto !important; - margin-left: auto !important; - overflow-y: hidden -} - -.MathJax::-webkit-scrollbar { - width: .3rem; - height: .3rem -} - -.MathJax::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: .25rem -} - -.MathJax::-webkit-scrollbar-thumb:hover { - background: #a0a0a0 -} - -p~div.math { - margin-top: -1.15rem -} - -blockquote { - margin: 1em; - padding: .2em 1.5em; - border-left: 4px solid #ccc -} - -blockquote.epigraph, -blockquote.highlights, -blockquote.pull-quote { - font-size: 1.25em; - border-left: none -} - -blockquote div>p { - margin-bottom: .5em -} - -blockquote div>p+p.attribution { - font-style: normal; - font-size: .9em; - text-align: right; - color: #6c757d; - padding-right: 2em -} - -aside.sidebar:not(.margin), -div.sidebar:not(.margin) { - background-color: unset; - padding: 1em; - border-radius: .4em; - border-color: #aaa -} - -@media (min-width:992px) { - - aside.sidebar:not(.margin), - div.sidebar:not(.margin) { - width: 65%; - margin: 0 -35% 0 3% - } -} - -div.tableofcontents-wrapper p.caption { - font-weight: 600 !important; - margin-bottom: 0 !important -} - -div.toctree-wrapper p.caption { - font-size: 1.4em -} - -div.toctree-wrapper>ul { - padding-left: 1.5em -} - -div.toctree-wrapper>ul>li>a { - font-size: 1.1em -} - -div.contents { - border-radius: .4em; - padding: 1em 1em 2em -} - -div.contents p.topic-title { - font-size: 1.5em; - padding: 0 0 0 .5em; - margin-bottom: 0 -} - -div.contents>ul { - list-style: none; - padding-left: 1em -} - -div.contents>ul>li>ul { - padding-left: 1.5em -} - -div.contents>ul>li>p>a { - font-size: 1.2em; - margin-bottom: .5em -} - -@media print { - #jb-print-toc { - margin-bottom: 1.5rem - } - - #jb-print-toc .section-nav { - border-left: 0; - list-style-type: disc; - margin-left: 3em - } - - #jb-print-toc .section-nav a { - text-decoration: none; - padding-left: 0 - } - - #jb-print-toc .section-nav li { - display: list-item !important - } - - #jb-print-toc .section-nav .nav { - display: none - } -} - -ul.ablog-archive, -ul.postlist { - padding-left: 0 -} - -ul.postlist>li>p:first-child { - font-size: 1.5em -} - -ul.postlist li+li { - margin-top: 2em -} - -ul.postlist li>p>a { - font-style: normal; - font-size: 1.3em -} - -div.bd-sidebar h2 { - font-size: 1.5em -} - -div.bd-sidebar h3 { - font-size: 1.4em -} - -div.bd-sidebar>ul { - list-style: none; - padding-left: 0 -} - -@media only print { - - div.utterances, - hypothesis-sidebar { - display: none - } -} - -div.cell div.highlight { - margin-bottom: 0 -} - -div.cell div.cell_input, -div.cell div.cell_output pre { - border-radius: .4em; - border: 1px solid #ccc -} - -div.cell div.cell_output { - padding-right: 0 -} - -div.cell.tag_output_scroll div.cell_output, -div.cell.tag_scroll-output div.cell_output { - max-height: 24em; - overflow-y: auto -} - -div.cell.tag_output_scroll div.cell_output::-webkit-scrollbar, -div.cell.tag_scroll-output div.cell_output::-webkit-scrollbar { - width: .3rem; - height: .3rem -} - -div.cell.tag_output_scroll div.cell_output::-webkit-scrollbar-thumb, -div.cell.tag_scroll-output div.cell_output::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: .25rem -} - -div.cell.tag_output_scroll div.cell_output::-webkit-scrollbar-thumb:hover, -div.cell.tag_scroll-output div.cell_output::-webkit-scrollbar-thumb:hover { - background: #a0a0a0 -} - -@media print { - - div.cell.tag_output_scroll div.cell_output, - div.cell.tag_scroll-output div.cell_output { - max-height: unset; - overflow-y: visible - } -} - -div.cell.tag_scroll-input div.cell_input { - max-height: 24em; - overflow-y: auto -} - -div.cell.tag_scroll-input div.cell_input::-webkit-scrollbar { - width: .3rem; - height: .3rem -} - -div.cell.tag_scroll-input div.cell_input::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: .25rem -} - -div.cell.tag_scroll-input div.cell_input::-webkit-scrollbar-thumb:hover { - background: #a0a0a0 -} - -@media print { - div.cell.tag_scroll-input div.cell_input { - max-height: unset; - overflow-y: visible - } -} - -div.sphinx-tabs>div.sphinx-menu { - padding: 0 -} - -div.sphinx-tabs>div.sphinx-menu>a.item { - width: auto; - margin: 0 0 -1px -} - -.bd-sidebar div#rtd-footer-container { - position: sticky; - bottom: 0 -} - -.bd-sidebar .rst-versions.rst-badge { - position: unset; - font-size: .9em -} - -.bd-sidebar .rst-versions.rst-badge .rst-current-version { - display: flex; - align-items: center; - gap: .2rem; - height: 2.5rem; - transition: background-color .2s ease-out; - background-color: #fff; - color: #5a5a5a; - border-top: 1px solid rgba(0, 0, 0, .1) -} - -@media (max-width:768px) { - .bd-sidebar .rst-versions.rst-badge .rst-current-version { - height: 3rem - } -} - -.bd-sidebar .rst-versions.rst-badge .rst-current-version:hover { - background-color: rgba(var(--pst-color-sidebar-expander-background-hover), 1); - cursor: pointer -} - -.bd-sidebar .rst-versions.rst-badge .rst-current-version .fa { - color: #5a5a5a -} - -.bd-sidebar .rst-versions.rst-badge .rst-current-version .fa-book { - float: unset; - margin-right: auto -} - -.bd-sidebar .rst-versions.rst-badge .rst-current-version .fa-book:after { - content: "Read the Docs"; - font-family: sans-serif; - font-weight: 700; - margin-left: .2em -} - -.bd-sidebar .rst-versions.rst-badge .rst-other-versions dt { - color: #ccc -} - -.thebelab-cell { - border: none !important; - margin-right: .5em !important -} - -.thebelab-cell .thebelab-input { - padding-left: 10px !important -} - -.cell.docutils.container { - padding-right: 0 !important -} - -button.thebe-launch-button { - height: 2.5em; - font-size: 1em -} - -#search-documentation, -#search-documentation~form, -#search-documentation~p { - display: none -} - -div#search-results>h2 { - margin-top: 0 -} - -ul.search { - margin: 0; - list-style: none -} - -ul.search li { - background-image: none; - margin-bottom: 1em; - padding: 0 0 1em; - border-bottom: 1px solid rgba(0, 0, 0, .1) -} - -ul.search li>a { - font-size: 1.2em -} - -ul.search li div.context, -ul.search li p.context { - margin: .5em 0 0 -} - -ul.search li div.context a:before, -ul.search li p.context a:before { - content: "#"; - padding-right: .2em; - color: #aaa -} \ No newline at end of file diff --git a/doc/rst/_css_helpers/sphinx-book-theme-1.1.2-orig.css b/doc/rst/_css_helpers/sphinx-book-theme-1.1.2-orig.css new file mode 100644 index 0000000000..edb63dbf72 --- /dev/null +++ b/doc/rst/_css_helpers/sphinx-book-theme-1.1.2-orig.css @@ -0,0 +1,981 @@ +/*! sphinx-book-theme CSS + * BSD 3-Clause License + * Copyright (c) 2020, EBP + * All rights reserved. + * + * This follows the 7-1 pattern described here: + * https://sass-guidelin.es/#architecture + */ +html[data-theme=dark], +html[data-theme=light] { + --pst-font-size-base: none; + --pst-color-secondary: #e89217 +} + +html[data-theme=light] { + --sbt-color-announcement: #616161; + --pst-color-primary: #176de8 +} + +html[data-theme=dark] { + --pst-color-primary: #528fe4; + --sbt-color-announcement: #616161; + --pst-color-background: #121212 +} + +html { + scroll-padding-top: 4rem +} + +.sbt-scroll-pixel-helper { + position: absolute; + width: 0; + height: 0; + top: 0; + left: 0 +} + +.d-n, +.onlyprint { + display: none +} + +@media print { + .onlyprint { + display: block !important + } +} + +@media print { + .noprint { + display: none !important + } +} + +.bd-article-container h1, +.bd-article-container h2, +.bd-article-container h3, +.bd-article-container h4, +.bd-article-container h5, +.bd-article-container p.caption { + color: var(--pst-color-muted) +} + +.bd-article-container h1, +.bd-article-container h2 { + font-weight: 500 +} + +a.brackets:before { + color: inherit; + font-family: inherit; + margin-right: 0 +} + +table { + position: relative +} + +@media print { + .bd-main .bd-content { + margin-left: 2rem; + height: auto + } + + .bd-main .bd-content #jb-print-docs-body { + margin-left: 0 + } + + .bd-main .bd-content #jb-print-docs-body h1 { + font-size: 3em; + text-align: center; + margin-bottom: 0 + } + + .bd-main .bd-content .bd-article { + padding-top: 0 + } + + .bd-main .bd-content .bd-article h1:first-of-type { + display: none + } + + .bd-main .bd-content .container { + min-width: 0 !important + } + + .bd-main .bd-content h1 { + margin-top: 1em; + margin-bottom: 1em + } + + .bd-main .bd-content h1, + .bd-main .bd-content h2, + .bd-main .bd-content h3, + .bd-main .bd-content h4 { + break-after: avoid; + color: #000 + } + + .bd-main .bd-content table { + break-inside: avoid + } + + .bd-main .bd-content pre { + word-wrap: break-word + } + + .bd-main .bd-content a.headerlink { + display: none + } + + .bd-main .bd-content aside.margin, + .bd-main .bd-content aside.sidebar, + .bd-main .bd-content blockquote.epigraph { + border: none + } + + .bd-main .bd-content .footer { + margin-top: 1em + } + + .bd-main .bd-content #jb-print-toc { + margin-bottom: 1.5rem; + margin-left: 0 + } + + .bd-main .bd-content #jb-print-toc .section-nav { + border-left: 0 !important; + list-style-type: disc !important; + margin-left: 3em !important + } + + .bd-main .bd-content #jb-print-toc .section-nav a { + text-decoration: none !important + } + + .bd-main .bd-content #jb-print-toc .section-nav li { + display: list-item !important + } + + .bd-main .bd-content #jb-print-toc .section-nav .nav { + display: none + } + + .bd-main .bd-footer-content { + display: none !important + } +} + +.bd-header-announcement { + background-color: var(--sbt-color-announcement); + color: #fff +} + +.bd-main .bd-content { + justify-content: left +} + +.bd-main .bd-content .bd-article-container { + padding: 0; + overflow-x: unset; + min-width: 0 +} + +@media (min-width:1200px) { + .bd-main .bd-content .bd-article-container { + max-width: calc(100% - var(--pst-sidebar-secondary)) + } +} + +.bd-main .bd-content .bd-article-container .bd-article { + padding-right: 2rem; + padding-left: 2rem +} + +@media (max-width:768px) { + .bd-main .bd-content .bd-article-container .bd-article { + padding-right: 1rem; + padding-left: 1rem + } +} + +.bd-main .bd-content .bd-article-container details.above-input summary, +.bd-main .bd-content .bd-article-container details.below-input summary { + border-left: 3px solid var(--pst-color-primary) +} + +@media (min-width:768px) { + label.sidebar-toggle.primary-toggle { + display: inline-block + } +} + +@media (max-width:768px) { + label.sidebar-toggle.primary-toggle { + margin-bottom: 0 + } +} + +@media (min-width:992px) { + label.sidebar-toggle.secondary-toggle { + display: none + } +} + +@media (max-width:768px) { + label.sidebar-toggle.secondary-toggle { + margin-bottom: 0 + } +} + +.bd-header-article { + display: flex; + align-items: center; + position: sticky; + top: 0; + background-color: var(--pst-color-background); + transition: left .2s; + font-size: .9em; + padding: 0 1rem; + z-index: 1020 +} + +@media (max-width:768px) { + .bd-header-article { + padding: 0 .5rem; + height: 3.5rem + } +} + +.scrolled .bd-header-article { + box-shadow: 0 6px 6px -6px var(--pst-color-shadow) +} + +.bd-header-article .header-article__inner { + padding: 0 +} + +.bd-header-article .header-article-items { + display: flex; + align-items: center; + height: 3rem; + width: 100% +} + +.bd-header-article .header-article-item { + display: flex; + align-items: center +} + +.bd-header-article .article-header-buttons { + display: flex +} + +.bd-header-article .btn { + font-size: 1.3rem; + color: var(--pst-color-text-muted); + border: none; + padding: 0 .5rem; + display: flex; + align-items: center +} + +.bd-header-article .btn svg { + width: 1.3rem +} + +.bd-header-article .btn.show, +.bd-header-article .btn:hover { + color: var(--pst-color-text-base); + border: none +} + +.bd-header-article .btn.show+.dropdown-menu, +.bd-header-article .btn:hover+.dropdown-menu { + display: block +} + +.bd-header-article .btn:focus { + box-shadow: none +} + +.bd-header-article .btn.dropdown-toggle:after { + display: none +} + +.bd-header-article div.dropdown { + display: flex; + align-items: center +} + +.bd-header-article .theme-switch-button { + margin: 0 +} + +.bd-header-article .theme-switch-button button, +.bd-header-article .theme-switch-button i, +.bd-header-article .theme-switch-button span { + padding: 0 +} + +.bd-header-article .theme-switch-button i, +.bd-header-article .theme-switch-button span { + transition: color .25s ease-out +} + +.bd-header-article .theme-switch-button:active, +.bd-header-article .theme-switch-button:hover { + background-color: unset !important +} + +.bd-header-article .theme-switch-button:active i, +.bd-header-article .theme-switch-button:active span, +.bd-header-article .theme-switch-button:hover i, +.bd-header-article .theme-switch-button:hover span { + color: var(--pst-color-text-base) +} + +.bd-header-article .dropdown-menu { + top: 2rem; + transform: translateX(-75%); + box-shadow: 0 .2rem .5rem var(--pst-color-shadow), 0 0 .0625rem var(--pst-color-shadow) !important; + border-color: var(--pst-color-border); + background-color: var(--pst-color-background); + color: var(--pst-color-text-muted) +} + +.bd-header-article .dropdown-menu:hover { + display: block +} + +.bd-header-article .dropdown-menu .dropdown-item { + display: inline-flex; + align-items: center; + padding-left: .5em; + font-size: 1em +} + +.bd-header-article .dropdown-menu .dropdown-item:hover { + text-decoration: none; + background-color: initial; + color: var(--pst-color-text-base) +} + +.bd-header-article .dropdown-menu .dropdown-item span img { + height: 1em +} + +.bd-header-article .dropdown-menu .dropdown-item span.btn__icon-container { + width: 1.7em; + align-items: center; + display: inline-flex; + justify-content: center +} + +.bd-header { + position: inherit +} + +.bd-header label.sidebar-toggle { + display: none +} + +.bd-sidebar-primary { + top: 0; + max-height: 100vh; + padding: 1rem; + transition: margin-left .25s ease 0s, opacity .25s ease 0s, visibility .25s ease 0s +} + +@media (max-width:768px) { + .bd-sidebar-primary { + z-index: 1081 + } +} + +.bd-sidebar-primary .sidebar-primary-items__start { + border-top: none +} + +@media (min-width:992px) { + .bd-sidebar-primary { + flex-basis: 20% + } +} + +@media (min-width:992px) { + input#__primary:checked~.bd-container .bd-sidebar-primary { + margin-left: -20%; + visibility: hidden; + opacity: 0 + } +} + +.bd-sidebar-secondary { + top: 0 +} + +@media (max-width:992px) { + .bd-sidebar-secondary { + z-index: 1081 + } +} + +.bd-sidebar-secondary .sidebar-secondary-items { + padding: 0; + display: flex; + gap: .5rem +} + +.bd-sidebar-secondary .sidebar-secondary-items .sidebar-secondary-item { + padding-top: 0; + padding-bottom: 0 +} + +.bd-sidebar-secondary .onthispage { + height: 3rem; + min-height: 3rem; + display: flex; + gap: .5rem; + align-items: center; + margin: 0; + color: var(--pst-color-muted) +} + +@media (min-width:992px) { + .bd-sidebar-secondary { + background: var(--pst-color-background); + height: fit-content; + transition: max-height .4s ease; + z-index: 2; + padding: 0 + } + + .bd-sidebar-secondary .toc-item { + border-left-color: var(--pst-color-surface); + padding-top: 0 + } + + .bd-sidebar-secondary .toc-item nav.page-toc { + margin-bottom: 0; + transition: opacity .4s ease + } + + .bd-sidebar-secondary.hide:not(:hover) { + max-height: 3rem; + overflow-y: hidden + } + + .scrolled .bd-sidebar-secondary.hide:not(:hover) { + box-shadow: 0 6px 6px -6px rgba(0, 0, 0, .3) + } + + .bd-sidebar-secondary.hide:not(:hover) .onthispage:after { + opacity: 1; + content: "\f107"; + font-family: Font Awesome\ 5 Free; + font-weight: 900; + padding-left: .5em; + transition: opacity .3s ease + } + + .bd-sidebar-secondary.hide:not(:hover) nav.page-toc { + opacity: 0 + } +} + +footer { + font-size: var(--sbt-font-size-small-1) +} + +footer.bd-footer-content { + display: flex; + flex-wrap: wrap; + padding: 15px; + border-top: 1px solid #ccc; + font-size: 87.5% +} + +footer.bd-footer-content .bd-footer-content__inner { + padding-left: 0 +} + +footer.bd-footer-content .bd-footer-content__inner p { + margin-bottom: 0 +} + +.bd-footer-article { + padding: 0 1rem +} + +@media (max-width:768px) { + .bd-footer-article { + padding: 0 .5rem + } +} + +#pst-back-to-top { + font-size: .8rem +} + +@media (min-width:1200px) { + #pst-back-to-top { + display: none !important + } +} + +.bd-sidebar-primary .navbar-icon-links { + column-gap: .5rem +} + +.bd-sidebar-primary .navbar-icon-links .nav-link i, +.bd-sidebar-primary .navbar-icon-links .nav-link span { + font-size: 1.2rem +} + +.bd-sidebar-primary .navbar-icon-links .nav-link img { + font-size: .8rem +} + +.navbar-brand { + height: unset; + max-height: unset; + flex-direction: column; + justify-content: center; + gap: .25rem +} + +.navbar-brand:hover { + text-decoration: none +} + +.navbar-brand .logo__title { + font-size: 1.25rem; + white-space: normal; + text-align: center +} + +.navbar-brand .logo__image { + height: unset +} + +.bd-search-container { + margin: 2em +} + +.bd-search-container #search-results h2:first-child { + display: none +} + +.search-button-field { + width: 100%; + font-size: .9rem; + display: none +} + +.search-button-field .search-button__kbd-shortcut { + margin-left: auto +} + +@media (min-width:992px) { + .search-button { + display: none !important + } + + .search-button-field { + display: flex + } +} + +div#searchbox { + padding-right: 2rem; + padding-left: 2rem +} + +@media (max-width:768px) { + div#searchbox { + padding-right: 1rem; + padding-left: 1rem + } +} + +@media (min-width:768px) { + div#searchbox p.highlight-link { + margin-left: 0 + } + + div#searchbox p.highlight-link a { + font-size: 1rem + } +} + +img { + max-width: 100% +} + +img.align-center { + margin-left: auto; + margin-right: auto; + display: block +} + +img.align-left { + clear: left; + float: left; + margin-right: 1em +} + +img.align-right { + clear: right; + float: right; + margin-left: 1em +} + +div.figure { + width: 100%; + margin-bottom: 1em; + text-align: center +} + +div.figure.align-left { + text-align: left +} + +div.figure.align-left p.caption { + margin-left: 0 +} + +div.figure.align-right { + text-align: right +} + +div.figure.align-right p.caption { + margin-right: 0 +} + +div.figure p.caption { + margin: .5em 10% +} + +div.figure.margin-caption p.caption, +div.figure.margin p.caption { + margin: .5em 0 +} + +div.figure.margin-caption p.caption { + text-align: left +} + +div.figure span.caption-number { + font-weight: 700 +} + +div.figure span { + font-size: .9rem +} + +label.margin-toggle { + margin-bottom: 0 +} + +label.margin-toggle.marginnote-label { + display: none +} + +label.margin-toggle sup { + user-select: none +} + +@media (max-width:992px) { + label.margin-toggle { + cursor: pointer; + color: #0071bc + } + + label.margin-toggle.marginnote-label { + display: inline + } + + label.margin-toggle.marginnote-label:after { + content: "\2295" + } +} + +input.margin-toggle { + display: none +} + +@media (max-width:992px) { + + input.margin-toggle:checked+.marginnote, + input.margin-toggle:checked+.sidenote { + display: block; + float: left; + left: 1rem; + clear: both; + width: 95%; + margin: 1rem 2.5%; + position: relative + } +} + +span.marginnote, +span.sidenote { + z-index: 2; + position: relative; + width: 40%; + float: right; + background-color: unset; + font-size: .9em; + margin-left: .5rem; + border-left: none +} + +span.marginnote sup, +span.sidenote sup { + user-select: none +} + +@media (min-width:992px), +print { + + span.marginnote, + span.sidenote { + width: 33%; + margin: 0 -36% 0 0; + clear: right + } + + span.marginnote p.sidebar-title, + span.sidenote p.sidebar-title { + margin-bottom: -1rem; + border-bottom: none; + padding-left: 0 + } + + span.marginnote p.sidebar-title~*, + span.sidenote p.sidebar-title~* { + padding-left: 0; + padding-right: 0 + } +} + +@media (max-width:992px) { + + span.marginnote, + span.sidenote { + display: none + } +} + +aside.sidebar .note { + margin: 1rem; + padding: 0 0 1rem +} + +aside.sidebar .admonition-title { + margin: 0 -1rem 0 0 +} + +aside.sidebar.margin .sidebar-title:empty { + display: none +} + +aside.sidebar.margin .admonition { + margin: .5rem; + padding-left: 0; + padding-right: 0 +} + +aside.sidebar.margin .admonition .admonition-title { + margin-left: 0; + margin-right: 0 +} + +@media (min-width:992px) { + aside.sidebar.margin { + border: none + } + + aside.sidebar.margin .admonition { + margin: 1rem 0; + padding: 0 0 1rem + } +} + +.cell.tag_margin, +.cell.tag_popout, +.margin.docutils.container, +aside.margin, +div.margin, +figure.margin { + z-index: 2; + position: relative; + width: 40%; + float: right; + background-color: unset; + font-size: .9em; + margin-left: .5rem +} + +@media (min-width:992px), +print { + + .cell.tag_margin, + .cell.tag_popout, + .margin.docutils.container, + aside.margin, + div.margin, + figure.margin { + width: 33%; + margin: 0 -36% 0 0; + clear: right + } + + .cell.tag_margin p.sidebar-title, + .cell.tag_popout p.sidebar-title, + .margin.docutils.container p.sidebar-title, + aside.margin p.sidebar-title, + div.margin p.sidebar-title, + figure.margin p.sidebar-title { + margin-bottom: -1rem; + border-bottom: none; + padding-left: 0 + } + + .cell.tag_margin p.sidebar-title~*, + .cell.tag_popout p.sidebar-title~*, + .margin.docutils.container p.sidebar-title~*, + aside.margin p.sidebar-title~*, + div.margin p.sidebar-title~*, + figure.margin p.sidebar-title~* { + padding-left: 0; + padding-right: 0 + } +} + +.cell.tag_margin div.cell.tag_margin .cell_output, +.cell.tag_popout div.cell.tag_margin .cell_output, +.margin.docutils.container div.cell.tag_margin .cell_output, +aside.margin div.cell.tag_margin .cell_output, +div.margin div.cell.tag_margin .cell_output, +figure.margin div.cell.tag_margin .cell_output { + padding-left: 0 +} + +div.figure.margin-caption figcaption, +div.figure.margin-caption p.caption, +figure.margin-caption figcaption { + z-index: 2; + position: relative; + width: 40%; + float: right; + background-color: unset; + font-size: .9em; + margin-left: .5rem +} + +@media (min-width:992px), +print { + + div.figure.margin-caption figcaption, + div.figure.margin-caption p.caption, + figure.margin-caption figcaption { + width: 33%; + margin: 0 -36% 0 0; + clear: right + } + + div.figure.margin-caption figcaption p.sidebar-title, + div.figure.margin-caption p.caption p.sidebar-title, + figure.margin-caption figcaption p.sidebar-title { + margin-bottom: -1rem; + border-bottom: none; + padding-left: 0 + } + + div.figure.margin-caption figcaption p.sidebar-title~*, + div.figure.margin-caption p.caption p.sidebar-title~*, + figure.margin-caption figcaption p.sidebar-title~* { + padding-left: 0; + padding-right: 0 + } +} + +.margin-caption figcaption { + text-align: left +} + +div.cell.tag_full-width, +div.cell.tag_full_width, +div.full-width, +div.full_width { + z-index: 2; + position: relative +} + +@media (min-width:992px) { + + div.cell.tag_full-width, + div.cell.tag_full_width, + div.full-width, + div.full_width { + max-width: 136%; + width: 136% + } +} + +blockquote.epigraph, +blockquote.highlights, +blockquote.pull-quote { + font-size: 1.25em; + border-left: none; + background-color: var(--pst-color-background) +} + +blockquote div>p+p.attribution { + font-style: normal; + font-size: .9em; + text-align: right; + color: #6c757d; + padding-right: 2em +} + +div[class*=highlight-], +pre { + clear: none +} + +div.cell.tag_output_scroll div.cell_output, +div.cell.tag_scroll-input div.cell_input, +div.cell.tag_scroll-output div.cell_output { + max-height: 24em; + overflow-y: auto +} + +@media only print { + + div.utterances, + hypothesis-sidebar { + display: none + } +} + +.thebelab-cell { + border: none !important; + margin-right: .5em !important +} + +.thebelab-cell .thebelab-input { + padding-left: 10px !important +} + +.cell.docutils.container { + padding-right: 0 !important +} + +button.thebe-launch-button { + height: 2.5em; + font-size: 1em +} \ No newline at end of file diff --git a/doc/rst/_css_helpers/tabs-3.4.5-orig.css b/doc/rst/_css_helpers/tabs-3.4.5-orig.css new file mode 100644 index 0000000000..957ba60d69 --- /dev/null +++ b/doc/rst/_css_helpers/tabs-3.4.5-orig.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/doc/rst/_css_helpers/typo3-theme.css b/doc/rst/_css_helpers/typo3-theme.css deleted file mode 100644 index 3deb0d2a77..0000000000 --- a/doc/rst/_css_helpers/typo3-theme.css +++ /dev/null @@ -1,13088 +0,0 @@ -/*! - * Bootstrap v4.4.1 (https://getbootstrap.com/) - * Copyright 2011-2019 The Bootstrap Authors - * Copyright 2011-2019 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -:root { - --blue: #007bff; - --indigo: #6610f2; - --purple: #6f42c1; - --pink: #e83e8c; - --red: #dc3545; - --orange: #fd7e14; - --yellow: #ffc107; - --green: #28a745; - --teal: #20c997; - --cyan: #17a2b8; - --white: #fff; - --gray: #6c6c6c; - --gray-dark: #313131; - --primary: #ff8700; - --secondary: #6c6c6c; - --success: #5cb85c; - --info: #5bc0de; - --warning: #f0ad4e; - --danger: #d9534f; - --light: #f2f2f2; - --dark: #313131; - --breakpoint-xs: 0; - --breakpoint-sm: 576px; - --breakpoint-md: 768px; - --breakpoint-lg: 992px; - --breakpoint-xl: 1200px; - --font-family-sans-serif: "Source Sans Pro", sans-serif; - --font-family-monospace: "Source Code Pro", monospace -} - -*, -*::before, -*::after { - box-sizing: border-box -} - -html { - font-family: sans-serif; - line-height: 1.15; - -webkit-text-size-adjust: 100%; - -webkit-tap-highlight-color: rgba(0, 0, 0, 0) -} - -article, -aside, -figcaption, -figure, -footer, -header, -hgroup, -main, -nav, -section { - display: block -} - -body { - margin: 0; - font-family: "Source Sans Pro", sans-serif; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - color: #212121; - text-align: left; - background-color: #fff -} - -[tabindex="-1"]:focus:not(:focus-visible) { - outline: 0 !important -} - -hr { - box-sizing: content-box; - height: 0; - overflow: visible -} - -h1, -h2, -h3, -h4, -h5, -h6 { - margin-top: 0; - margin-bottom: .5em -} - -p { - margin-top: 0; - margin-bottom: 1rem -} - -abbr[title], -abbr[data-original-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 -} - -ol, -ul, -dl { - margin-top: 0; - margin-bottom: 1rem -} - -ol ol, -ul ul, -ol ul, -ul ol { - margin-bottom: 0 -} - -dt { - font-weight: 600 -} - -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: #ff8700; - text-decoration: none; - background-color: transparent -} - -a:hover { - color: #b35f00; - text-decoration: underline -} - -a:not([href]) { - color: inherit; - text-decoration: none -} - -a:not([href]):hover { - color: inherit; - text-decoration: none -} - -pre, -code, -kbd, -samp { - font-family: "Source Code Pro", 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: #6c6c6c; - 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 -} - -input, -button, -select, -optgroup, -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 -} - -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button -} - -button:not(:disabled), -[type="button"]:not(:disabled), -[type="reset"]:not(:disabled), -[type="submit"]:not(:disabled) { - cursor: pointer -} - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - padding: 0; - border-style: none -} - -input[type="radio"], -input[type="checkbox"] { - box-sizing: border-box; - padding: 0 -} - -input[type="date"], -input[type="time"], -input[type="datetime-local"], -input[type="month"] { - -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: .5em; - font-weight: 600; - line-height: 1.2 -} - -h1, -.h1 { - font-size: 2em -} - -h2, -.h2 { - font-size: 1.75em -} - -h3, -.h3 { - font-size: 1.5em -} - -h4, -.h4 { - font-size: 1.25em -} - -h5, -.h5 { - font-size: 1em -} - -h6, -.h6 { - font-size: .85em -} - -.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, 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: #6c6c6c -} - -.blockquote-footer::before { - content: "\2014\00A0" -} - -.img-fluid { - max-width: 100%; - height: auto -} - -.img-thumbnail { - padding: .25rem; - background-color: #fff; - border: 1px solid #dedede; - 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: #6c6c6c -} - -code { - font-size: 87.5%; - color: #ff5370; - word-wrap: break-word -} - -a>code { - color: inherit -} - -kbd { - padding: .2rem .4rem; - font-size: 87.5%; - color: #fff; - background-color: #212121; - border-radius: .2rem -} - -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: 600 -} - -pre { - display: block; - font-size: 87.5%; - color: #212121 -} - -pre code { - font-size: inherit; - color: inherit; - word-break: normal -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll -} - -.container { - width: 100%; - padding-right: 20px; - padding-left: 20px; - 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, -.container-sm, -.container-md, -.container-lg, -.container-xl { - width: 100%; - padding-right: 20px; - padding-left: 20px; - margin-right: auto; - margin-left: auto -} - -@media (min-width: 576px) { - - .container, - .container-sm { - max-width: 540px - } -} - -@media (min-width: 768px) { - - .container, - .container-sm, - .container-md { - max-width: 720px - } -} - -@media (min-width: 992px) { - - .container, - .container-sm, - .container-md, - .container-lg { - max-width: 960px - } -} - -@media (min-width: 1200px) { - - .container, - .container-sm, - .container-md, - .container-lg, - .container-xl { - max-width: 1140px - } -} - -.row { - display: flex; - flex-wrap: wrap; - margin-right: -20px; - margin-left: -20px -} - -.no-gutters { - margin-right: 0; - margin-left: 0 -} - -.no-gutters>.col, -.no-gutters>[class*="col-"] { - padding-right: 0; - padding-left: 0 -} - -.col-1, -.col-2, -.col-3, -.col-4, -.col-5, -.col-6, -.col-7, -.col-8, -.col-9, -.col-10, -.col-11, -.col-12, -.col, -.col-auto, -.col-sm-1, -.col-sm-2, -.col-sm-3, -.col-sm-4, -.col-sm-5, -.col-sm-6, -.col-sm-7, -.col-sm-8, -.col-sm-9, -.col-sm-10, -.col-sm-11, -.col-sm-12, -.col-sm, -.col-sm-auto, -.col-md-1, -.col-md-2, -.col-md-3, -.col-md-4, -.col-md-5, -.col-md-6, -.col-md-7, -.col-md-8, -.col-md-9, -.col-md-10, -.col-md-11, -.col-md-12, -.col-md, -.col-md-auto, -.col-lg-1, -.col-lg-2, -.col-lg-3, -.col-lg-4, -.col-lg-5, -.col-lg-6, -.col-lg-7, -.col-lg-8, -.col-lg-9, -.col-lg-10, -.col-lg-11, -.col-lg-12, -.col-lg, -.col-lg-auto, -.col-xl-1, -.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-10, -.col-xl-11, -.col-xl-12, -.col-xl, -.col-xl-auto { - position: relative; - width: 100%; - padding-right: 20px; - padding-left: 20px -} - -.col { - flex-basis: 0; - flex-grow: 1; - max-width: 100% -} - -.row-cols-1>* { - flex: 0 0 100%; - max-width: 100% -} - -.row-cols-2>* { - flex: 0 0 50%; - max-width: 50% -} - -.row-cols-3>* { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% -} - -.row-cols-4>* { - flex: 0 0 25%; - max-width: 25% -} - -.row-cols-5>* { - flex: 0 0 20%; - max-width: 20% -} - -.row-cols-6>* { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% -} - -.col-auto { - flex: 0 0 auto; - width: auto; - max-width: 100% -} - -.col-1 { - flex: 0 0 8.3333333333%; - max-width: 8.3333333333% -} - -.col-2 { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% -} - -.col-3 { - flex: 0 0 25%; - max-width: 25% -} - -.col-4 { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% -} - -.col-5 { - flex: 0 0 41.6666666667%; - max-width: 41.6666666667% -} - -.col-6 { - flex: 0 0 50%; - max-width: 50% -} - -.col-7 { - flex: 0 0 58.3333333333%; - max-width: 58.3333333333% -} - -.col-8 { - flex: 0 0 66.6666666667%; - max-width: 66.6666666667% -} - -.col-9 { - flex: 0 0 75%; - max-width: 75% -} - -.col-10 { - flex: 0 0 83.3333333333%; - max-width: 83.3333333333% -} - -.col-11 { - flex: 0 0 91.6666666667%; - max-width: 91.6666666667% -} - -.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.3333333333% -} - -.offset-2 { - margin-left: 16.6666666667% -} - -.offset-3 { - margin-left: 25% -} - -.offset-4 { - margin-left: 33.3333333333% -} - -.offset-5 { - margin-left: 41.6666666667% -} - -.offset-6 { - margin-left: 50% -} - -.offset-7 { - margin-left: 58.3333333333% -} - -.offset-8 { - margin-left: 66.6666666667% -} - -.offset-9 { - margin-left: 75% -} - -.offset-10 { - margin-left: 83.3333333333% -} - -.offset-11 { - margin-left: 91.6666666667% -} - -@media (min-width: 576px) { - .col-sm { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-sm-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-sm-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-sm-3>* { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .row-cols-sm-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-sm-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-sm-6>* { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-sm-auto { - flex: 0 0 auto; - width: auto; - max-width: 100% - } - - .col-sm-1 { - flex: 0 0 8.3333333333%; - max-width: 8.3333333333% - } - - .col-sm-2 { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-sm-3 { - flex: 0 0 25%; - max-width: 25% - } - - .col-sm-4 { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .col-sm-5 { - flex: 0 0 41.6666666667%; - max-width: 41.6666666667% - } - - .col-sm-6 { - flex: 0 0 50%; - max-width: 50% - } - - .col-sm-7 { - flex: 0 0 58.3333333333%; - max-width: 58.3333333333% - } - - .col-sm-8 { - flex: 0 0 66.6666666667%; - max-width: 66.6666666667% - } - - .col-sm-9 { - flex: 0 0 75%; - max-width: 75% - } - - .col-sm-10 { - flex: 0 0 83.3333333333%; - max-width: 83.3333333333% - } - - .col-sm-11 { - flex: 0 0 91.6666666667%; - max-width: 91.6666666667% - } - - .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.3333333333% - } - - .offset-sm-2 { - margin-left: 16.6666666667% - } - - .offset-sm-3 { - margin-left: 25% - } - - .offset-sm-4 { - margin-left: 33.3333333333% - } - - .offset-sm-5 { - margin-left: 41.6666666667% - } - - .offset-sm-6 { - margin-left: 50% - } - - .offset-sm-7 { - margin-left: 58.3333333333% - } - - .offset-sm-8 { - margin-left: 66.6666666667% - } - - .offset-sm-9 { - margin-left: 75% - } - - .offset-sm-10 { - margin-left: 83.3333333333% - } - - .offset-sm-11 { - margin-left: 91.6666666667% - } -} - -@media (min-width: 768px) { - .col-md { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-md-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-md-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-md-3>* { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .row-cols-md-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-md-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-md-6>* { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-md-auto { - flex: 0 0 auto; - width: auto; - max-width: 100% - } - - .col-md-1 { - flex: 0 0 8.3333333333%; - max-width: 8.3333333333% - } - - .col-md-2 { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-md-3 { - flex: 0 0 25%; - max-width: 25% - } - - .col-md-4 { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .col-md-5 { - flex: 0 0 41.6666666667%; - max-width: 41.6666666667% - } - - .col-md-6 { - flex: 0 0 50%; - max-width: 50% - } - - .col-md-7 { - flex: 0 0 58.3333333333%; - max-width: 58.3333333333% - } - - .col-md-8 { - flex: 0 0 66.6666666667%; - max-width: 66.6666666667% - } - - .col-md-9 { - flex: 0 0 75%; - max-width: 75% - } - - .col-md-10 { - flex: 0 0 83.3333333333%; - max-width: 83.3333333333% - } - - .col-md-11 { - flex: 0 0 91.6666666667%; - max-width: 91.6666666667% - } - - .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.3333333333% - } - - .offset-md-2 { - margin-left: 16.6666666667% - } - - .offset-md-3 { - margin-left: 25% - } - - .offset-md-4 { - margin-left: 33.3333333333% - } - - .offset-md-5 { - margin-left: 41.6666666667% - } - - .offset-md-6 { - margin-left: 50% - } - - .offset-md-7 { - margin-left: 58.3333333333% - } - - .offset-md-8 { - margin-left: 66.6666666667% - } - - .offset-md-9 { - margin-left: 75% - } - - .offset-md-10 { - margin-left: 83.3333333333% - } - - .offset-md-11 { - margin-left: 91.6666666667% - } -} - -@media (min-width: 992px) { - .col-lg { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-lg-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-lg-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-lg-3>* { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .row-cols-lg-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-lg-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-lg-6>* { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-lg-auto { - flex: 0 0 auto; - width: auto; - max-width: 100% - } - - .col-lg-1 { - flex: 0 0 8.3333333333%; - max-width: 8.3333333333% - } - - .col-lg-2 { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-lg-3 { - flex: 0 0 25%; - max-width: 25% - } - - .col-lg-4 { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .col-lg-5 { - flex: 0 0 41.6666666667%; - max-width: 41.6666666667% - } - - .col-lg-6 { - flex: 0 0 50%; - max-width: 50% - } - - .col-lg-7 { - flex: 0 0 58.3333333333%; - max-width: 58.3333333333% - } - - .col-lg-8 { - flex: 0 0 66.6666666667%; - max-width: 66.6666666667% - } - - .col-lg-9 { - flex: 0 0 75%; - max-width: 75% - } - - .col-lg-10 { - flex: 0 0 83.3333333333%; - max-width: 83.3333333333% - } - - .col-lg-11 { - flex: 0 0 91.6666666667%; - max-width: 91.6666666667% - } - - .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.3333333333% - } - - .offset-lg-2 { - margin-left: 16.6666666667% - } - - .offset-lg-3 { - margin-left: 25% - } - - .offset-lg-4 { - margin-left: 33.3333333333% - } - - .offset-lg-5 { - margin-left: 41.6666666667% - } - - .offset-lg-6 { - margin-left: 50% - } - - .offset-lg-7 { - margin-left: 58.3333333333% - } - - .offset-lg-8 { - margin-left: 66.6666666667% - } - - .offset-lg-9 { - margin-left: 75% - } - - .offset-lg-10 { - margin-left: 83.3333333333% - } - - .offset-lg-11 { - margin-left: 91.6666666667% - } -} - -@media (min-width: 1200px) { - .col-xl { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-xl-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-xl-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-xl-3>* { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .row-cols-xl-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-xl-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-xl-6>* { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-xl-auto { - flex: 0 0 auto; - width: auto; - max-width: 100% - } - - .col-xl-1 { - flex: 0 0 8.3333333333%; - max-width: 8.3333333333% - } - - .col-xl-2 { - flex: 0 0 16.6666666667%; - max-width: 16.6666666667% - } - - .col-xl-3 { - flex: 0 0 25%; - max-width: 25% - } - - .col-xl-4 { - flex: 0 0 33.3333333333%; - max-width: 33.3333333333% - } - - .col-xl-5 { - flex: 0 0 41.6666666667%; - max-width: 41.6666666667% - } - - .col-xl-6 { - flex: 0 0 50%; - max-width: 50% - } - - .col-xl-7 { - flex: 0 0 58.3333333333%; - max-width: 58.3333333333% - } - - .col-xl-8 { - flex: 0 0 66.6666666667%; - max-width: 66.6666666667% - } - - .col-xl-9 { - flex: 0 0 75%; - max-width: 75% - } - - .col-xl-10 { - flex: 0 0 83.3333333333%; - max-width: 83.3333333333% - } - - .col-xl-11 { - flex: 0 0 91.6666666667%; - max-width: 91.6666666667% - } - - .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.3333333333% - } - - .offset-xl-2 { - margin-left: 16.6666666667% - } - - .offset-xl-3 { - margin-left: 25% - } - - .offset-xl-4 { - margin-left: 33.3333333333% - } - - .offset-xl-5 { - margin-left: 41.6666666667% - } - - .offset-xl-6 { - margin-left: 50% - } - - .offset-xl-7 { - margin-left: 58.3333333333% - } - - .offset-xl-8 { - margin-left: 66.6666666667% - } - - .offset-xl-9 { - margin-left: 75% - } - - .offset-xl-10 { - margin-left: 83.3333333333% - } - - .offset-xl-11 { - margin-left: 91.6666666667% - } -} - -.table, -table.docutils:not(.field-list) { - width: 100%; - margin-bottom: 1rem; - color: #212121; - background-color: #fff -} - -.table th, -table.docutils:not(.field-list) th, -.table td, -table.docutils:not(.field-list) td { - padding: .75rem; - vertical-align: top; - border-top: 1px solid #dedede -} - -.table thead th, -table.docutils:not(.field-list) thead th { - vertical-align: bottom; - border-bottom: 2px solid #dedede -} - -.table tbody+tbody, -table.docutils:not(.field-list) tbody+tbody { - border-top: 2px solid #dedede -} - -.table-sm th, -.table-sm td { - padding: .3rem -} - -.table-bordered, -table.docutils:not(.field-list) { - border: 1px solid #dedede -} - -.table-bordered th, -table.docutils:not(.field-list) th, -.table-bordered td, -table.docutils:not(.field-list) td { - border: 1px solid #dedede -} - -.table-bordered thead th, -table.docutils:not(.field-list) thead th, -.table-bordered thead td, -table.docutils:not(.field-list) thead td { - border-bottom-width: 2px -} - -.table-borderless th, -.table-borderless td, -.table-borderless thead th, -.table-borderless tbody+tbody { - border: 0 -} - -.table-striped tbody tr:nth-of-type(odd), -table.docutils:not(.field-list) tbody tr:nth-of-type(odd) { - background-color: rgba(0, 0, 0, 0.05) -} - -.table-hover tbody tr:hover { - color: #212121; - background-color: rgba(0, 0, 0, 0.075) -} - -.table-primary, -.table-primary>th, -.table-primary>td { - background-color: #ffddb8 -} - -.table-primary th, -.table-primary td, -.table-primary thead th, -.table-primary tbody+tbody { - border-color: #ffc17a -} - -.table-hover .table-primary:hover { - background-color: #ffd19f -} - -.table-hover .table-primary:hover>td, -.table-hover .table-primary:hover>th { - background-color: #ffd19f -} - -.table-secondary, -.table-secondary>th, -.table-secondary>td { - background-color: #d6d6d6 -} - -.table-secondary th, -.table-secondary td, -.table-secondary thead th, -.table-secondary tbody+tbody { - border-color: #b3b3b3 -} - -.table-hover .table-secondary:hover { - background-color: #c9c9c9 -} - -.table-hover .table-secondary:hover>td, -.table-hover .table-secondary:hover>th { - background-color: #c9c9c9 -} - -.table-success, -.table-success>th, -.table-success>td { - background-color: #d1ebd1 -} - -.table-success th, -.table-success td, -.table-success thead th, -.table-success tbody+tbody { - border-color: #aadaaa -} - -.table-hover .table-success:hover { - background-color: #bfe3bf -} - -.table-hover .table-success:hover>td, -.table-hover .table-success:hover>th { - background-color: #bfe3bf -} - -.table-info, -.table-info>th, -.table-info>td { - background-color: #d1edf6 -} - -.table-info th, -.table-info td, -.table-info thead th, -.table-info tbody+tbody { - border-color: #aadeee -} - -.table-hover .table-info:hover { - background-color: #bce5f2 -} - -.table-hover .table-info:hover>td, -.table-hover .table-info:hover>th { - background-color: #bce5f2 -} - -.table-warning, -.table-warning>th, -.table-warning>td { - background-color: #fbe8cd -} - -.table-warning th, -.table-warning td, -.table-warning thead th, -.table-warning tbody+tbody { - border-color: #f7d4a3 -} - -.table-hover .table-warning:hover { - background-color: #f9ddb5 -} - -.table-hover .table-warning:hover>td, -.table-hover .table-warning:hover>th { - background-color: #f9ddb5 -} - -.table-danger, -.table-danger>th, -.table-danger>td { - background-color: #f4cfce -} - -.table-danger th, -.table-danger td, -.table-danger thead th, -.table-danger tbody+tbody { - border-color: #eba6a3 -} - -.table-hover .table-danger:hover { - background-color: #efbbb9 -} - -.table-hover .table-danger:hover>td, -.table-hover .table-danger:hover>th { - background-color: #efbbb9 -} - -.table-light, -.table-light>th, -.table-light>td { - background-color: #fbfbfb -} - -.table-light th, -.table-light td, -.table-light thead th, -.table-light tbody+tbody { - border-color: #f8f8f8 -} - -.table-hover .table-light:hover { - background-color: #eee -} - -.table-hover .table-light:hover>td, -.table-hover .table-light:hover>th { - background-color: #eee -} - -.table-dark, -.table-dark>th, -.table-dark>td { - background-color: #c5c5c5 -} - -.table-dark th, -.table-dark td, -.table-dark thead th, -.table-dark tbody+tbody { - border-color: #949494 -} - -.table-hover .table-dark:hover { - background-color: #b8b8b8 -} - -.table-hover .table-dark:hover>td, -.table-hover .table-dark:hover>th { - background-color: #b8b8b8 -} - -.table-active, -.table-active>th, -.table-active>td { - background-color: rgba(0, 0, 0, 0.075) -} - -.table-hover .table-active:hover { - background-color: rgba(0, 0, 0, 0.075) -} - -.table-hover .table-active:hover>td, -.table-hover .table-active:hover>th { - background-color: rgba(0, 0, 0, 0.075) -} - -.table .thead-dark th, -table.docutils:not(.field-list) .thead-dark th { - color: #fff; - background-color: #313131; - border-color: #444 -} - -.table .thead-light th, -table.docutils:not(.field-list) .thead-light th, -table.docutils:not(.field-list) thead th { - color: #494949; - background-color: #e9e9e9; - border-color: #dedede -} - -.table-dark { - color: #fff; - background-color: #313131 -} - -.table-dark th, -.table-dark td, -.table-dark thead th { - border-color: #444 -} - -.table-dark.table-bordered, -table.table-dark.docutils:not(.field-list) { - border: 0 -} - -.table-dark.table-striped tbody tr:nth-of-type(odd), -table.table-dark.docutils:not(.field-list) tbody tr:nth-of-type(odd) { - background-color: rgba(255, 255, 255, 0.05) -} - -.table-dark.table-hover tbody tr:hover { - color: #fff; - background-color: rgba(255, 255, 255, 0.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, - .table-responsive-sm>table.docutils:not(.field-list) { - 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, - .table-responsive-md>table.docutils:not(.field-list) { - 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, - .table-responsive-lg>table.docutils:not(.field-list) { - 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, - .table-responsive-xl>table.docutils:not(.field-list) { - border: 0 - } -} - -.table-responsive { - display: block; - width: 100%; - overflow-x: auto; - -webkit-overflow-scrolling: touch -} - -.table-responsive>.table-bordered, -.table-responsive>table.docutils:not(.field-list) { - 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: #494949; - background-color: #fff; - background-clip: padding-box; - border: 1px solid #cecece; - border-radius: .25rem; - transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out -} - -@media (prefers-reduced-motion: reduce) { - .form-control { - transition: none - } -} - -.form-control::-ms-expand { - background-color: transparent; - border: 0 -} - -.form-control:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #494949 -} - -.form-control:focus { - color: #494949; - background-color: #fff; - border-color: #ffc380; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.form-control::placeholder { - color: #6c6c6c; - opacity: 1 -} - -.form-control:disabled, -.form-control[readonly] { - background-color: #e9e9e9; - opacity: 1 -} - -select.form-control:focus::-ms-value { - color: #494949; - 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: .375rem 0; - margin-bottom: 0; - font-size: 1rem; - line-height: 1.5; - color: #212121; - background-color: transparent; - border: solid transparent; - border-width: 1px 0 -} - -.form-control-plaintext.form-control-sm, -.form-control-plaintext.form-control-lg { - 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[size], -select.form-control[multiple] { - 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, -.form-check-input:disabled~.form-check-label { - color: #6c6c6c -} - -.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: #5cb85c -} - -.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(92, 184, 92, 0.9); - border-radius: .25rem -} - -.was-validated :valid~.valid-feedback, -.was-validated :valid~.valid-tooltip, -.is-valid~.valid-feedback, -.is-valid~.valid-tooltip { - display: block -} - -.was-validated .form-control:valid, -.form-control.is-valid { - border-color: #5cb85c; - padding-right: calc(1.5em + .75rem); - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%235cb85c' 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: right calc(.375em + .1875rem) center; - background-size: calc(.75em + .375rem) calc(.75em + .375rem) -} - -.was-validated .form-control:valid:focus, -.form-control.is-valid:focus { - border-color: #5cb85c; - box-shadow: 0 0 0 .2rem rgba(92, 184, 92, 0.25) -} - -.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) -} - -.was-validated .custom-select:valid, -.custom-select.is-valid { - border-color: #5cb85c; - padding-right: calc(.75em + 2.3125rem); - background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23313131' 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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%235cb85c' 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) -} - -.was-validated .custom-select:valid:focus, -.custom-select.is-valid:focus { - border-color: #5cb85c; - box-shadow: 0 0 0 .2rem rgba(92, 184, 92, 0.25) -} - -.was-validated .form-check-input:valid~.form-check-label, -.form-check-input.is-valid~.form-check-label { - color: #5cb85c -} - -.was-validated .form-check-input:valid~.valid-feedback, -.was-validated .form-check-input:valid~.valid-tooltip, -.form-check-input.is-valid~.valid-feedback, -.form-check-input.is-valid~.valid-tooltip { - display: block -} - -.was-validated .custom-control-input:valid~.custom-control-label, -.custom-control-input.is-valid~.custom-control-label { - color: #5cb85c -} - -.was-validated .custom-control-input:valid~.custom-control-label::before, -.custom-control-input.is-valid~.custom-control-label::before { - border-color: #5cb85c -} - -.was-validated .custom-control-input:valid:checked~.custom-control-label::before, -.custom-control-input.is-valid:checked~.custom-control-label::before { - border-color: #80c780; - background-color: #80c780 -} - -.was-validated .custom-control-input:valid:focus~.custom-control-label::before, -.custom-control-input.is-valid:focus~.custom-control-label::before { - box-shadow: 0 0 0 .2rem rgba(92, 184, 92, 0.25) -} - -.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before, -.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before { - border-color: #5cb85c -} - -.was-validated .custom-file-input:valid~.custom-file-label, -.custom-file-input.is-valid~.custom-file-label { - border-color: #5cb85c -} - -.was-validated .custom-file-input:valid:focus~.custom-file-label, -.custom-file-input.is-valid:focus~.custom-file-label { - border-color: #5cb85c; - box-shadow: 0 0 0 .2rem rgba(92, 184, 92, 0.25) -} - -.invalid-feedback { - display: none; - width: 100%; - margin-top: .25rem; - font-size: 80%; - color: #d9534f -} - -.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(217, 83, 79, 0.9); - border-radius: .25rem -} - -.was-validated :invalid~.invalid-feedback, -.was-validated :invalid~.invalid-tooltip, -.is-invalid~.invalid-feedback, -.is-invalid~.invalid-tooltip { - display: block -} - -.was-validated .form-control:invalid, -.form-control.is-invalid { - border-color: #d9534f; - padding-right: calc(1.5em + .75rem); - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23d9534f' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23d9534f' stroke='none'/%3e%3c/svg%3e"); - background-repeat: no-repeat; - background-position: right calc(.375em + .1875rem) center; - background-size: calc(.75em + .375rem) calc(.75em + .375rem) -} - -.was-validated .form-control:invalid:focus, -.form-control.is-invalid:focus { - border-color: #d9534f; - box-shadow: 0 0 0 .2rem rgba(217, 83, 79, 0.25) -} - -.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) -} - -.was-validated .custom-select:invalid, -.custom-select.is-invalid { - border-color: #d9534f; - padding-right: calc(.75em + 2.3125rem); - background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23313131' 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' width='12' height='12' fill='none' stroke='%23d9534f' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23d9534f' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) -} - -.was-validated .custom-select:invalid:focus, -.custom-select.is-invalid:focus { - border-color: #d9534f; - box-shadow: 0 0 0 .2rem rgba(217, 83, 79, 0.25) -} - -.was-validated .form-check-input:invalid~.form-check-label, -.form-check-input.is-invalid~.form-check-label { - color: #d9534f -} - -.was-validated .form-check-input:invalid~.invalid-feedback, -.was-validated .form-check-input:invalid~.invalid-tooltip, -.form-check-input.is-invalid~.invalid-feedback, -.form-check-input.is-invalid~.invalid-tooltip { - display: block -} - -.was-validated .custom-control-input:invalid~.custom-control-label, -.custom-control-input.is-invalid~.custom-control-label { - color: #d9534f -} - -.was-validated .custom-control-input:invalid~.custom-control-label::before, -.custom-control-input.is-invalid~.custom-control-label::before { - border-color: #d9534f -} - -.was-validated .custom-control-input:invalid:checked~.custom-control-label::before, -.custom-control-input.is-invalid:checked~.custom-control-label::before { - border-color: #e27c79; - background-color: #e27c79 -} - -.was-validated .custom-control-input:invalid:focus~.custom-control-label::before, -.custom-control-input.is-invalid:focus~.custom-control-label::before { - box-shadow: 0 0 0 .2rem rgba(217, 83, 79, 0.25) -} - -.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before, -.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before { - border-color: #d9534f -} - -.was-validated .custom-file-input:invalid~.custom-file-label, -.custom-file-input.is-invalid~.custom-file-label { - border-color: #d9534f -} - -.was-validated .custom-file-input:invalid:focus~.custom-file-label, -.custom-file-input.is-invalid:focus~.custom-file-label { - border-color: #d9534f; - box-shadow: 0 0 0 .2rem rgba(217, 83, 79, 0.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 .input-group, - .form-inline .custom-select { - 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, -.toc-toggle { - display: inline-block; - font-weight: 400; - color: #212121; - text-align: center; - vertical-align: middle; - cursor: pointer; - 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 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out -} - -@media (prefers-reduced-motion: reduce) { - - .btn, - .toc-toggle { - transition: none - } -} - -.btn:hover, -.toc-toggle:hover { - color: #212121; - text-decoration: none -} - -.btn:focus, -.toc-toggle:focus, -.btn.focus, -.focus.toc-toggle { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.btn.disabled, -.disabled.toc-toggle, -.btn:disabled, -.toc-toggle:disabled { - opacity: .65 -} - -a.btn.disabled, -a.disabled.toc-toggle, -fieldset:disabled a.btn, -fieldset:disabled a.toc-toggle { - pointer-events: none -} - -.btn-primary { - color: #fff; - background-color: #ff8700; - border-color: #ff8700 -} - -.btn-primary:hover { - color: #fff; - background-color: #d97300; - border-color: #cc6c00 -} - -.btn-primary:focus, -.btn-primary.focus { - color: #fff; - background-color: #d97300; - border-color: #cc6c00; - box-shadow: 0 0 0 .2rem rgba(255, 153, 38, 0.5) -} - -.btn-primary.disabled, -.btn-primary:disabled { - color: #fff; - background-color: #ff8700; - border-color: #ff8700 -} - -.btn-primary:not(:disabled):not(.disabled):active, -.btn-primary:not(:disabled):not(.disabled).active, -.show>.btn-primary.dropdown-toggle { - color: #fff; - background-color: #cc6c00; - border-color: #bf6500 -} - -.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(255, 153, 38, 0.5) -} - -.btn-secondary { - color: #fff; - background-color: #6c6c6c; - border-color: #6c6c6c -} - -.btn-secondary:hover { - color: #fff; - background-color: #595959; - border-color: #535252 -} - -.btn-secondary:focus, -.btn-secondary.focus { - color: #fff; - background-color: #595959; - border-color: #535252; - box-shadow: 0 0 0 .2rem rgba(130, 130, 130, 0.5) -} - -.btn-secondary.disabled, -.btn-secondary:disabled { - color: #fff; - background-color: #6c6c6c; - border-color: #6c6c6c -} - -.btn-secondary:not(:disabled):not(.disabled):active, -.btn-secondary:not(:disabled):not(.disabled).active, -.show>.btn-secondary.dropdown-toggle { - color: #fff; - background-color: #535252; - border-color: #4c4c4c -} - -.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, 130, 130, 0.5) -} - -.btn-success { - color: #fff; - background-color: #5cb85c; - border-color: #5cb85c -} - -.btn-success:hover { - color: #fff; - background-color: #48a648; - border-color: #449d44 -} - -.btn-success:focus, -.btn-success.focus { - color: #fff; - background-color: #48a648; - border-color: #449d44; - box-shadow: 0 0 0 .2rem rgba(116, 195, 116, 0.5) -} - -.btn-success.disabled, -.btn-success:disabled { - color: #fff; - background-color: #5cb85c; - border-color: #5cb85c -} - -.btn-success:not(:disabled):not(.disabled):active, -.btn-success:not(:disabled):not(.disabled).active, -.show>.btn-success.dropdown-toggle { - color: #fff; - background-color: #449d44; - border-color: #409440 -} - -.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(116, 195, 116, 0.5) -} - -.btn-info { - color: #212121; - background-color: #5bc0de; - border-color: #5bc0de -} - -.btn-info:hover { - color: #fff; - background-color: #3bb4d8; - border-color: #31b0d5 -} - -.btn-info:focus, -.btn-info.focus { - color: #fff; - background-color: #3bb4d8; - border-color: #31b0d5; - box-shadow: 0 0 0 .2rem rgba(82, 168, 194, 0.5) -} - -.btn-info.disabled, -.btn-info:disabled { - color: #212121; - background-color: #5bc0de; - border-color: #5bc0de -} - -.btn-info:not(:disabled):not(.disabled):active, -.btn-info:not(:disabled):not(.disabled).active, -.show>.btn-info.dropdown-toggle { - color: #fff; - background-color: #31b0d5; - border-color: #2aaacf -} - -.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(82, 168, 194, 0.5) -} - -.btn-warning { - color: #212121; - background-color: #f0ad4e; - border-color: #f0ad4e -} - -.btn-warning:hover { - color: #212121; - background-color: #ed9d2b; - border-color: #ec971f -} - -.btn-warning:focus, -.btn-warning.focus { - color: #212121; - background-color: #ed9d2b; - border-color: #ec971f; - box-shadow: 0 0 0 .2rem rgba(209, 152, 71, 0.5) -} - -.btn-warning.disabled, -.btn-warning:disabled { - color: #212121; - background-color: #f0ad4e; - border-color: #f0ad4e -} - -.btn-warning:not(:disabled):not(.disabled):active, -.btn-warning:not(:disabled):not(.disabled).active, -.show>.btn-warning.dropdown-toggle { - color: #212121; - background-color: #ec971f; - border-color: #ea9214 -} - -.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(209, 152, 71, 0.5) -} - -.btn-danger { - color: #fff; - background-color: #d9534f; - border-color: #d9534f -} - -.btn-danger:hover { - color: #fff; - background-color: #d23430; - border-color: #c9302c -} - -.btn-danger:focus, -.btn-danger.focus { - color: #fff; - background-color: #d23430; - border-color: #c9302c; - box-shadow: 0 0 0 .2rem rgba(223, 109, 105, 0.5) -} - -.btn-danger.disabled, -.btn-danger:disabled { - color: #fff; - background-color: #d9534f; - border-color: #d9534f -} - -.btn-danger:not(:disabled):not(.disabled):active, -.btn-danger:not(:disabled):not(.disabled).active, -.show>.btn-danger.dropdown-toggle { - color: #fff; - background-color: #c9302c; - border-color: #bf2e29 -} - -.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(223, 109, 105, 0.5) -} - -.btn-light, -.toc-toggle { - color: #212121; - background-color: #f2f2f2; - border-color: #f2f2f2 -} - -.btn-light:hover, -.toc-toggle:hover { - color: #212121; - background-color: #dfdfdf; - border-color: #d9d8d8 -} - -.btn-light:focus, -.toc-toggle:focus, -.btn-light.focus, -.focus.toc-toggle { - color: #212121; - background-color: #dfdfdf; - border-color: #d9d8d8; - box-shadow: 0 0 0 .2rem rgba(211, 211, 211, 0.5) -} - -.btn-light.disabled, -.disabled.toc-toggle, -.btn-light:disabled, -.toc-toggle:disabled { - color: #212121; - background-color: #f2f2f2; - border-color: #f2f2f2 -} - -.btn-light:not(:disabled):not(.disabled):active, -.toc-toggle:not(:disabled):not(.disabled):active, -.btn-light:not(:disabled):not(.disabled).active, -.toc-toggle:not(:disabled):not(.disabled).active, -.show>.btn-light.dropdown-toggle, -.show>.dropdown-toggle.toc-toggle { - color: #212121; - background-color: #d9d8d8; - border-color: #d2d2d2 -} - -.btn-light:not(:disabled):not(.disabled):active:focus, -.toc-toggle:not(:disabled):not(.disabled):active:focus, -.btn-light:not(:disabled):not(.disabled).active:focus, -.toc-toggle:not(:disabled):not(.disabled).active:focus, -.show>.btn-light.dropdown-toggle:focus, -.show>.dropdown-toggle.toc-toggle:focus { - box-shadow: 0 0 0 .2rem rgba(211, 211, 211, 0.5) -} - -.btn-dark { - color: #fff; - background-color: #313131; - border-color: #313131 -} - -.btn-dark:hover { - color: #fff; - background-color: #1e1e1e; - border-color: #181717 -} - -.btn-dark:focus, -.btn-dark.focus { - color: #fff; - background-color: #1e1e1e; - border-color: #181717; - box-shadow: 0 0 0 .2rem rgba(80, 80, 80, 0.5) -} - -.btn-dark.disabled, -.btn-dark:disabled { - color: #fff; - background-color: #313131; - border-color: #313131 -} - -.btn-dark:not(:disabled):not(.disabled):active, -.btn-dark:not(:disabled):not(.disabled).active, -.show>.btn-dark.dropdown-toggle { - color: #fff; - background-color: #181717; - border-color: #111 -} - -.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(80, 80, 80, 0.5) -} - -.btn-outline-primary { - color: #ff8700; - border-color: #ff8700 -} - -.btn-outline-primary:hover { - color: #fff; - background-color: #ff8700; - border-color: #ff8700 -} - -.btn-outline-primary:focus, -.btn-outline-primary.focus { - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.5) -} - -.btn-outline-primary.disabled, -.btn-outline-primary:disabled { - color: #ff8700; - 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: #ff8700; - border-color: #ff8700 -} - -.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(255, 135, 0, 0.5) -} - -.btn-outline-secondary { - color: #6c6c6c; - border-color: #6c6c6c -} - -.btn-outline-secondary:hover { - color: #fff; - background-color: #6c6c6c; - border-color: #6c6c6c -} - -.btn-outline-secondary:focus, -.btn-outline-secondary.focus { - box-shadow: 0 0 0 .2rem rgba(108, 108, 108, 0.5) -} - -.btn-outline-secondary.disabled, -.btn-outline-secondary:disabled { - color: #6c6c6c; - 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: #6c6c6c; - border-color: #6c6c6c -} - -.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, 108, 108, 0.5) -} - -.btn-outline-success { - color: #5cb85c; - border-color: #5cb85c -} - -.btn-outline-success:hover { - color: #fff; - background-color: #5cb85c; - border-color: #5cb85c -} - -.btn-outline-success:focus, -.btn-outline-success.focus { - box-shadow: 0 0 0 .2rem rgba(92, 184, 92, 0.5) -} - -.btn-outline-success.disabled, -.btn-outline-success:disabled { - color: #5cb85c; - 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: #5cb85c; - border-color: #5cb85c -} - -.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(92, 184, 92, 0.5) -} - -.btn-outline-info { - color: #5bc0de; - border-color: #5bc0de -} - -.btn-outline-info:hover { - color: #212121; - background-color: #5bc0de; - border-color: #5bc0de -} - -.btn-outline-info:focus, -.btn-outline-info.focus { - box-shadow: 0 0 0 .2rem rgba(91, 192, 222, 0.5) -} - -.btn-outline-info.disabled, -.btn-outline-info:disabled { - color: #5bc0de; - 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: #212121; - background-color: #5bc0de; - border-color: #5bc0de -} - -.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(91, 192, 222, 0.5) -} - -.btn-outline-warning { - color: #f0ad4e; - border-color: #f0ad4e -} - -.btn-outline-warning:hover { - color: #212121; - background-color: #f0ad4e; - border-color: #f0ad4e -} - -.btn-outline-warning:focus, -.btn-outline-warning.focus { - box-shadow: 0 0 0 .2rem rgba(240, 173, 78, 0.5) -} - -.btn-outline-warning.disabled, -.btn-outline-warning:disabled { - color: #f0ad4e; - 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: #212121; - background-color: #f0ad4e; - border-color: #f0ad4e -} - -.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(240, 173, 78, 0.5) -} - -.btn-outline-danger { - color: #d9534f; - border-color: #d9534f -} - -.btn-outline-danger:hover { - color: #fff; - background-color: #d9534f; - border-color: #d9534f -} - -.btn-outline-danger:focus, -.btn-outline-danger.focus { - box-shadow: 0 0 0 .2rem rgba(217, 83, 79, 0.5) -} - -.btn-outline-danger.disabled, -.btn-outline-danger:disabled { - color: #d9534f; - 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: #d9534f; - border-color: #d9534f -} - -.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(217, 83, 79, 0.5) -} - -.btn-outline-light { - color: #f2f2f2; - border-color: #f2f2f2 -} - -.btn-outline-light:hover { - color: #212121; - background-color: #f2f2f2; - border-color: #f2f2f2 -} - -.btn-outline-light:focus, -.btn-outline-light.focus { - box-shadow: 0 0 0 .2rem rgba(242, 242, 242, 0.5) -} - -.btn-outline-light.disabled, -.btn-outline-light:disabled { - color: #f2f2f2; - 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: #212121; - background-color: #f2f2f2; - border-color: #f2f2f2 -} - -.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(242, 242, 242, 0.5) -} - -.btn-outline-dark { - color: #313131; - border-color: #313131 -} - -.btn-outline-dark:hover { - color: #fff; - background-color: #313131; - border-color: #313131 -} - -.btn-outline-dark:focus, -.btn-outline-dark.focus { - box-shadow: 0 0 0 .2rem rgba(49, 49, 49, 0.5) -} - -.btn-outline-dark.disabled, -.btn-outline-dark:disabled { - color: #313131; - 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: #313131; - border-color: #313131 -} - -.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(49, 49, 49, 0.5) -} - -.btn-link { - font-weight: 400; - color: #ff8700; - text-decoration: none -} - -.btn-link:hover { - color: #b35f00; - text-decoration: underline -} - -.btn-link:focus, -.btn-link.focus { - text-decoration: underline; - box-shadow: none -} - -.btn-link:disabled, -.btn-link.disabled { - color: #6c6c6c; - pointer-events: none -} - -.btn-lg, -.btn-group-lg>.btn, -.btn-group-lg>.toc-toggle { - padding: .5rem 1rem; - font-size: 1.25rem; - line-height: 1.5; - border-radius: .3rem -} - -.btn-sm, -.btn-group-sm>.btn, -.btn-group-sm>.toc-toggle { - 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="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100% -} - -.fade { - transition: opacity 0.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 0.35s ease -} - -@media (prefers-reduced-motion: reduce) { - .collapsing { - transition: none - } -} - -.dropup, -.dropright, -.dropdown, -.dropleft { - 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: #212121; - text-align: left; - list-style: none; - background-color: #fff; - background-clip: padding-box; - border: 1px solid rgba(0, 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^="top"], -.dropdown-menu[x-placement^="right"], -.dropdown-menu[x-placement^="bottom"], -.dropdown-menu[x-placement^="left"] { - right: auto; - bottom: auto -} - -.dropdown-divider { - height: 0; - margin: .5rem 0; - overflow: hidden; - border-top: 1px solid #e9e9e9 -} - -.dropdown-item { - display: block; - width: 100%; - padding: .25rem 1.5rem; - clear: both; - font-weight: 400; - color: #212121; - text-align: inherit; - white-space: nowrap; - background-color: transparent; - border: 0 -} - -.dropdown-item:hover, -.dropdown-item:focus { - color: #141414; - text-decoration: none; - background-color: #f2f2f2 -} - -.dropdown-item.active, -.dropdown-item:active { - color: #fff; - text-decoration: none; - background-color: #ff8700 -} - -.dropdown-item.disabled, -.dropdown-item:disabled { - color: #6c6c6c; - 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: #6c6c6c; - white-space: nowrap -} - -.dropdown-item-text { - display: block; - padding: .25rem 1.5rem; - color: #212121 -} - -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-flex; - vertical-align: middle -} - -.btn-group>.btn, -.btn-group>.toc-toggle, -.btn-group-vertical>.btn, -.btn-group-vertical>.toc-toggle { - position: relative; - flex: 1 1 auto -} - -.btn-group>.btn:hover, -.btn-group>.toc-toggle:hover, -.btn-group-vertical>.btn:hover, -.btn-group-vertical>.toc-toggle:hover { - z-index: 1 -} - -.btn-group>.btn:focus, -.btn-group>.toc-toggle:focus, -.btn-group>.btn:active, -.btn-group>.toc-toggle:active, -.btn-group>.btn.active, -.btn-group>.active.toc-toggle, -.btn-group-vertical>.btn:focus, -.btn-group-vertical>.toc-toggle:focus, -.btn-group-vertical>.btn:active, -.btn-group-vertical>.toc-toggle:active, -.btn-group-vertical>.btn.active, -.btn-group-vertical>.active.toc-toggle { - z-index: 1 -} - -.btn-toolbar { - display: flex; - flex-wrap: wrap; - justify-content: flex-start -} - -.btn-toolbar .input-group { - width: auto -} - -.btn-group>.btn:not(:first-child), -.btn-group>.toc-toggle:not(:first-child), -.btn-group>.btn-group:not(:first-child) { - margin-left: -1px -} - -.btn-group>.btn:not(:last-child):not(.dropdown-toggle), -.btn-group>.toc-toggle:not(:last-child):not(.dropdown-toggle), -.btn-group>.btn-group:not(:last-child)>.btn, -.btn-group>.btn-group:not(:last-child)>.toc-toggle { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.btn-group>.btn:not(:first-child), -.btn-group>.toc-toggle:not(:first-child), -.btn-group>.btn-group:not(:first-child)>.btn, -.btn-group>.btn-group:not(:first-child)>.toc-toggle { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.dropdown-toggle-split { - padding-right: .5625rem; - padding-left: .5625rem -} - -.dropdown-toggle-split::after, -.dropup .dropdown-toggle-split::after, -.dropright .dropdown-toggle-split::after { - margin-left: 0 -} - -.dropleft .dropdown-toggle-split::before { - margin-right: 0 -} - -.btn-sm+.dropdown-toggle-split, -.btn-group-sm>.btn+.dropdown-toggle-split, -.btn-group-sm>.toc-toggle+.dropdown-toggle-split { - padding-right: .375rem; - padding-left: .375rem -} - -.btn-lg+.dropdown-toggle-split, -.btn-group-lg>.btn+.dropdown-toggle-split, -.btn-group-lg>.toc-toggle+.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>.toc-toggle, -.btn-group-vertical>.btn-group { - width: 100% -} - -.btn-group-vertical>.btn:not(:first-child), -.btn-group-vertical>.toc-toggle:not(:first-child), -.btn-group-vertical>.btn-group:not(:first-child) { - margin-top: -1px -} - -.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle), -.btn-group-vertical>.toc-toggle:not(:last-child):not(.dropdown-toggle), -.btn-group-vertical>.btn-group:not(:last-child)>.btn, -.btn-group-vertical>.btn-group:not(:last-child)>.toc-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.btn-group-vertical>.btn:not(:first-child), -.btn-group-vertical>.toc-toggle:not(:first-child), -.btn-group-vertical>.btn-group:not(:first-child)>.btn, -.btn-group-vertical>.btn-group:not(:first-child)>.toc-toggle { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.btn-group-toggle>.btn, -.btn-group-toggle>.toc-toggle, -.btn-group-toggle>.btn-group>.btn, -.btn-group-toggle>.btn-group>.toc-toggle { - margin-bottom: 0 -} - -.btn-group-toggle>.btn input[type="radio"], -.btn-group-toggle>.toc-toggle input[type="radio"], -.btn-group-toggle>.btn input[type="checkbox"], -.btn-group-toggle>.toc-toggle input[type="checkbox"], -.btn-group-toggle>.btn-group>.btn input[type="radio"], -.btn-group-toggle>.btn-group>.toc-toggle input[type="radio"], -.btn-group-toggle>.btn-group>.btn input[type="checkbox"], -.btn-group-toggle>.btn-group>.toc-toggle input[type="checkbox"] { - 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>.form-control, -.input-group>.form-control-plaintext, -.input-group>.custom-select, -.input-group>.custom-file { - position: relative; - flex: 1 1 0%; - min-width: 0; - margin-bottom: 0 -} - -.input-group>.form-control+.form-control, -.input-group>.form-control+.custom-select, -.input-group>.form-control+.custom-file, -.input-group>.form-control-plaintext+.form-control, -.input-group>.form-control-plaintext+.custom-select, -.input-group>.form-control-plaintext+.custom-file, -.input-group>.custom-select+.form-control, -.input-group>.custom-select+.custom-select, -.input-group>.custom-select+.custom-file, -.input-group>.custom-file+.form-control, -.input-group>.custom-file+.custom-select, -.input-group>.custom-file+.custom-file { - margin-left: -1px -} - -.input-group>.form-control:focus, -.input-group>.custom-select:focus, -.input-group>.custom-file .custom-file-input:focus~.custom-file-label { - z-index: 3 -} - -.input-group>.custom-file .custom-file-input:focus { - z-index: 4 -} - -.input-group>.form-control:not(:last-child), -.input-group>.custom-select:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.input-group>.form-control:not(:first-child), -.input-group>.custom-select: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-prepend, -.input-group-append { - display: flex -} - -.input-group-prepend .btn, -.input-group-prepend .toc-toggle, -.input-group-append .btn, -.input-group-append .toc-toggle { - position: relative; - z-index: 2 -} - -.input-group-prepend .btn:focus, -.input-group-prepend .toc-toggle:focus, -.input-group-append .btn:focus, -.input-group-append .toc-toggle:focus { - z-index: 3 -} - -.input-group-prepend .btn+.btn, -.input-group-prepend .toc-toggle+.btn, -.input-group-prepend .btn+.toc-toggle, -.input-group-prepend .toc-toggle+.toc-toggle, -.input-group-prepend .btn+.input-group-text, -.input-group-prepend .toc-toggle+.input-group-text, -.input-group-prepend .input-group-text+.input-group-text, -.input-group-prepend .input-group-text+.btn, -.input-group-prepend .input-group-text+.toc-toggle, -.input-group-append .btn+.btn, -.input-group-append .toc-toggle+.btn, -.input-group-append .btn+.toc-toggle, -.input-group-append .toc-toggle+.toc-toggle, -.input-group-append .btn+.input-group-text, -.input-group-append .toc-toggle+.input-group-text, -.input-group-append .input-group-text+.input-group-text, -.input-group-append .input-group-text+.btn, -.input-group-append .input-group-text+.toc-toggle { - 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: #494949; - text-align: center; - white-space: nowrap; - background-color: #e9e9e9; - border: 1px solid #cecece; - border-radius: .25rem -} - -.input-group-text input[type="radio"], -.input-group-text input[type="checkbox"] { - margin-top: 0 -} - -.input-group-lg>.form-control:not(textarea), -.input-group-lg>.custom-select { - height: calc(1.5em + 1rem + 2px) -} - -.input-group-lg>.form-control, -.input-group-lg>.custom-select, -.input-group-lg>.input-group-prepend>.input-group-text, -.input-group-lg>.input-group-append>.input-group-text, -.input-group-lg>.input-group-prepend>.btn, -.input-group-lg>.input-group-prepend>.toc-toggle, -.input-group-lg>.input-group-append>.btn, -.input-group-lg>.input-group-append>.toc-toggle { - padding: .5rem 1rem; - font-size: 1.25rem; - line-height: 1.5; - border-radius: .3rem -} - -.input-group-sm>.form-control:not(textarea), -.input-group-sm>.custom-select { - height: calc(1.5em + .5rem + 2px) -} - -.input-group-sm>.form-control, -.input-group-sm>.custom-select, -.input-group-sm>.input-group-prepend>.input-group-text, -.input-group-sm>.input-group-append>.input-group-text, -.input-group-sm>.input-group-prepend>.btn, -.input-group-sm>.input-group-prepend>.toc-toggle, -.input-group-sm>.input-group-append>.btn, -.input-group-sm>.input-group-append>.toc-toggle { - 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-prepend>.btn, -.input-group>.input-group-prepend>.toc-toggle, -.input-group>.input-group-prepend>.input-group-text, -.input-group>.input-group-append:not(:last-child)>.btn, -.input-group>.input-group-append:not(:last-child)>.toc-toggle, -.input-group>.input-group-append:not(:last-child)>.input-group-text, -.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle), -.input-group>.input-group-append:last-child>.toc-toggle:not(:last-child):not(.dropdown-toggle), -.input-group>.input-group-append:last-child>.input-group-text:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.input-group>.input-group-append>.btn, -.input-group>.input-group-append>.toc-toggle, -.input-group>.input-group-append>.input-group-text, -.input-group>.input-group-prepend:not(:first-child)>.btn, -.input-group>.input-group-prepend:not(:first-child)>.toc-toggle, -.input-group>.input-group-prepend:not(:first-child)>.input-group-text, -.input-group>.input-group-prepend:first-child>.btn:not(:first-child), -.input-group>.input-group-prepend:first-child>.toc-toggle:not(:first-child), -.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child) { - 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; - left: 0; - z-index: -1; - width: 1rem; - height: 1.25rem; - opacity: 0 -} - -.custom-control-input:checked~.custom-control-label::before { - color: #fff; - border-color: #ff8700; - background-color: #ff8700 -} - -.custom-control-input:focus~.custom-control-label::before { - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.custom-control-input:focus:not(:checked)~.custom-control-label::before { - border-color: #ffc380 -} - -.custom-control-input:not(:disabled):active~.custom-control-label::before { - color: #fff; - background-color: #ffdbb3; - border-color: #ffdbb3 -} - -.custom-control-input[disabled]~.custom-control-label, -.custom-control-input:disabled~.custom-control-label { - color: #6c6c6c -} - -.custom-control-input[disabled]~.custom-control-label::before, -.custom-control-input:disabled~.custom-control-label::before { - background-color: #e9e9e9 -} - -.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: #ababab 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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e") -} - -.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before { - border-color: #ff8700; - background-color: #ff8700 -} - -.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' width='4' height='4' 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(255, 135, 0, 0.5) -} - -.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before { - background-color: rgba(255, 135, 0, 0.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' width='12' height='12' 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(255, 135, 0, 0.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: #ababab; - border-radius: .5rem; - transition: transform 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.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(255, 135, 0, 0.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: #494949; - vertical-align: middle; - background: #fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23313131' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px; - border: 1px solid #cecece; - border-radius: .25rem; - appearance: none -} - -.custom-select:focus { - border-color: #ffc380; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.custom-select:focus::-ms-value { - color: #494949; - background-color: #fff -} - -.custom-select[multiple], -.custom-select[size]:not([size="1"]) { - height: auto; - padding-right: .75rem; - background-image: none -} - -.custom-select:disabled { - color: #6c6c6c; - background-color: #e9e9e9 -} - -.custom-select::-ms-expand { - display: none -} - -.custom-select:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #494949 -} - -.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: #ffc380; - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.custom-file-input[disabled]~.custom-file-label, -.custom-file-input:disabled~.custom-file-label { - background-color: #e9e9e9 -} - -.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: #494949; - background-color: #fff; - border: 1px solid #cecece; - 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: #494949; - content: "Browse"; - background-color: #e9e9e9; - border-left: inherit; - border-radius: 0 .25rem .25rem 0 -} - -.custom-range { - width: 100%; - height: 1.4rem; - padding: 0; - background-color: transparent; - appearance: none -} - -.custom-range:focus { - outline: none -} - -.custom-range:focus::-webkit-slider-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.custom-range:focus::-moz-range-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.custom-range:focus::-ms-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(255, 135, 0, 0.25) -} - -.custom-range::-moz-focus-outer { - border: 0 -} - -.custom-range::-webkit-slider-thumb { - width: 1rem; - height: 1rem; - margin-top: -.25rem; - background-color: #ff8700; - border: 0; - border-radius: 1rem; - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.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: #ffdbb3 -} - -.custom-range::-webkit-slider-runnable-track { - width: 100%; - height: .5rem; - color: transparent; - cursor: pointer; - background-color: #dedede; - border-color: transparent; - border-radius: 1rem -} - -.custom-range::-moz-range-thumb { - width: 1rem; - height: 1rem; - background-color: #ff8700; - border: 0; - border-radius: 1rem; - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.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: #ffdbb3 -} - -.custom-range::-moz-range-track { - width: 100%; - height: .5rem; - color: transparent; - cursor: pointer; - background-color: #dedede; - 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: #ff8700; - border: 0; - border-radius: 1rem; - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; - appearance: none -} - -@media (prefers-reduced-motion: reduce) { - .custom-range::-ms-thumb { - transition: none - } -} - -.custom-range::-ms-thumb:active { - background-color: #ffdbb3 -} - -.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: #dedede; - border-radius: 1rem -} - -.custom-range::-ms-fill-upper { - margin-right: 15px; - background-color: #dedede; - border-radius: 1rem -} - -.custom-range:disabled::-webkit-slider-thumb { - background-color: #ababab -} - -.custom-range:disabled::-webkit-slider-runnable-track { - cursor: default -} - -.custom-range:disabled::-moz-range-thumb { - background-color: #ababab -} - -.custom-range:disabled::-moz-range-track { - cursor: default -} - -.custom-range:disabled::-ms-thumb { - background-color: #ababab -} - -.custom-control-label::before, -.custom-file-label, -.custom-select { - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.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:hover, -.nav-link:focus { - text-decoration: none -} - -.nav-link.disabled { - color: #6c6c6c; - pointer-events: none; - cursor: default -} - -.nav-tabs { - border-bottom: 1px solid #dedede -} - -.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:hover, -.nav-tabs .nav-link:focus { - border-color: #e9e9e9 #e9e9e9 #dedede -} - -.nav-tabs .nav-link.disabled { - color: #6c6c6c; - background-color: transparent; - border-color: transparent -} - -.nav-tabs .nav-link.active, -.nav-tabs .nav-item.show .nav-link { - color: #494949; - background-color: #fff; - border-color: #dedede #dedede #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: #ff8700 -} - -.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, -.navbar .container-sm, -.navbar .container-md, -.navbar .container-lg, -.navbar .container-xl { - 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:hover, -.navbar-brand:focus { - 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:hover, -.navbar-toggler:focus { - 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, - .navbar-expand-sm>.container-sm, - .navbar-expand-sm>.container-md, - .navbar-expand-sm>.container-lg, - .navbar-expand-sm>.container-xl { - 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, - .navbar-expand-sm>.container-sm, - .navbar-expand-sm>.container-md, - .navbar-expand-sm>.container-lg, - .navbar-expand-sm>.container-xl { - 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, - .navbar-expand-md>.container-sm, - .navbar-expand-md>.container-md, - .navbar-expand-md>.container-lg, - .navbar-expand-md>.container-xl { - 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, - .navbar-expand-md>.container-sm, - .navbar-expand-md>.container-md, - .navbar-expand-md>.container-lg, - .navbar-expand-md>.container-xl { - 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, - .navbar-expand-lg>.container-sm, - .navbar-expand-lg>.container-md, - .navbar-expand-lg>.container-lg, - .navbar-expand-lg>.container-xl { - 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, - .navbar-expand-lg>.container-sm, - .navbar-expand-lg>.container-md, - .navbar-expand-lg>.container-lg, - .navbar-expand-lg>.container-xl { - 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, - .navbar-expand-xl>.container-sm, - .navbar-expand-xl>.container-md, - .navbar-expand-xl>.container-lg, - .navbar-expand-xl>.container-xl { - 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, - .navbar-expand-xl>.container-sm, - .navbar-expand-xl>.container-md, - .navbar-expand-xl>.container-lg, - .navbar-expand-xl>.container-xl { - 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, -.navbar-expand>.container-sm, -.navbar-expand>.container-md, -.navbar-expand>.container-lg, -.navbar-expand>.container-xl { - 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, -.navbar-expand>.container-sm, -.navbar-expand>.container-md, -.navbar-expand>.container-lg, -.navbar-expand>.container-xl { - 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, 0.9) -} - -.navbar-light .navbar-brand:hover, -.navbar-light .navbar-brand:focus { - color: rgba(0, 0, 0, 0.9) -} - -.navbar-light .navbar-nav .nav-link { - color: rgba(0, 0, 0, 0.5) -} - -.navbar-light .navbar-nav .nav-link:hover, -.navbar-light .navbar-nav .nav-link:focus { - color: rgba(0, 0, 0, 0.7) -} - -.navbar-light .navbar-nav .nav-link.disabled { - color: rgba(0, 0, 0, 0.3) -} - -.navbar-light .navbar-nav .show>.nav-link, -.navbar-light .navbar-nav .active>.nav-link, -.navbar-light .navbar-nav .nav-link.show, -.navbar-light .navbar-nav .nav-link.active { - color: rgba(0, 0, 0, 0.9) -} - -.navbar-light .navbar-toggler { - color: rgba(0, 0, 0, 0.5); - border-color: rgba(0, 0, 0, 0.1) -} - -.navbar-light .navbar-toggler-icon { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(0,0,0,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") -} - -.navbar-light .navbar-text { - color: rgba(0, 0, 0, 0.5) -} - -.navbar-light .navbar-text a { - color: rgba(0, 0, 0, 0.9) -} - -.navbar-light .navbar-text a:hover, -.navbar-light .navbar-text a:focus { - color: rgba(0, 0, 0, 0.9) -} - -.navbar-dark .navbar-brand { - color: #fff -} - -.navbar-dark .navbar-brand:hover, -.navbar-dark .navbar-brand:focus { - color: #fff -} - -.navbar-dark .navbar-nav .nav-link { - color: rgba(255, 255, 255, 0.5) -} - -.navbar-dark .navbar-nav .nav-link:hover, -.navbar-dark .navbar-nav .nav-link:focus { - color: rgba(255, 255, 255, 0.75) -} - -.navbar-dark .navbar-nav .nav-link.disabled { - color: rgba(255, 255, 255, 0.25) -} - -.navbar-dark .navbar-nav .show>.nav-link, -.navbar-dark .navbar-nav .active>.nav-link, -.navbar-dark .navbar-nav .nav-link.show, -.navbar-dark .navbar-nav .nav-link.active { - color: #fff -} - -.navbar-dark .navbar-toggler { - color: rgba(255, 255, 255, 0.5); - border-color: rgba(255, 255, 255, 0.1) -} - -.navbar-dark .navbar-toggler-icon { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba(255,255,255,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") -} - -.navbar-dark .navbar-text { - color: rgba(255, 255, 255, 0.5) -} - -.navbar-dark .navbar-text a { - color: #fff -} - -.navbar-dark .navbar-text a:hover, -.navbar-dark .navbar-text a:focus { - 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, 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; - min-height: 1px; - padding: 1.25rem -} - -.card-title { - margin-bottom: 1.25rem -} - -.card-subtitle { - margin-top: -.625rem; - 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: 1.25rem 1.25rem; - margin-bottom: 0; - background-color: rgba(0, 0, 0, 0.03); - border-bottom: 1px solid rgba(0, 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: 1.25rem 1.25rem; - background-color: rgba(0, 0, 0, 0.03); - border-top: 1px solid rgba(0, 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: -1.25rem; - 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, -.card-img-top, -.card-img-bottom { - flex-shrink: 0; - width: 100% -} - -.card-img, -.card-img-top { - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.card-img, -.card-img-bottom { - border-bottom-right-radius: calc(.25rem - 1px); - border-bottom-left-radius: calc(.25rem - 1px) -} - -.card-deck .card { - margin-bottom: 20px -} - -@media (min-width: 576px) { - .card-deck { - display: flex; - flex-flow: row wrap; - margin-right: -20px; - margin-left: -20px - } - - .card-deck .card { - flex: 1 0 0%; - margin-right: 20px; - margin-bottom: 0; - margin-left: 20px - } -} - -.card-group>.card { - margin-bottom: 20px -} - -@media (min-width: 576px) { - .card-group { - display: flex; - 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-img-top, - .card-group>.card:not(:last-child) .card-header { - border-top-right-radius: 0 - } - - .card-group>.card:not(:last-child) .card-img-bottom, - .card-group>.card:not(:last-child) .card-footer { - 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-img-top, - .card-group>.card:not(:first-child) .card-header { - border-top-left-radius: 0 - } - - .card-group>.card:not(:first-child) .card-img-bottom, - .card-group>.card:not(:first-child) .card-footer { - border-bottom-left-radius: 0 - } -} - -.card-columns .card { - margin-bottom: 1.25rem -} - -@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(:last-of-type) { - border-bottom: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.accordion>.card:not(:first-of-type) { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.accordion>.card>.card-header { - border-radius: 0; - margin-bottom: -1px -} - -.breadcrumb { - display: flex; - flex-wrap: wrap; - padding: .75rem 1rem; - margin-bottom: 1rem; - list-style: none; - background-color: #e9e9e9; - border-radius: .25rem -} - -.breadcrumb-item+.breadcrumb-item { - padding-left: .5rem -} - -.breadcrumb-item+.breadcrumb-item::before { - display: inline-block; - padding-right: .5rem; - color: #6c6c6c; - content: "/" -} - -.breadcrumb-item+.breadcrumb-item:hover::before { - text-decoration: underline -} - -.breadcrumb-item+.breadcrumb-item:hover::before { - text-decoration: none -} - -.breadcrumb-item.active { - color: #6c6c6c -} - -.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: #ff8700; - background-color: #fff; - border: 1px solid #dedede -} - -.page-link:hover { - z-index: 2; - color: #b35f00; - text-decoration: none; - background-color: #e9e9e9; - border-color: #dedede -} - -.page-link:focus { - z-index: 3; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.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: 3; - color: #fff; - background-color: #ff8700; - border-color: #ff8700 -} - -.page-item.disabled .page-link { - color: #6c6c6c; - pointer-events: none; - cursor: auto; - background-color: #fff; - border-color: #dedede -} - -.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: 600; - line-height: 1; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25rem; - transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out -} - -@media (prefers-reduced-motion: reduce) { - .badge { - transition: none - } -} - -a.badge:hover, -a.badge:focus { - text-decoration: none -} - -.badge:empty { - display: none -} - -.btn .badge, -.toc-toggle .badge { - position: relative; - top: -1px -} - -.badge-pill { - padding-right: .6em; - padding-left: .6em; - border-radius: 10rem -} - -.badge-primary { - color: #fff; - background-color: #ff8700 -} - -a.badge-primary:hover, -a.badge-primary:focus { - color: #fff; - background-color: #cc6c00 -} - -a.badge-primary:focus, -a.badge-primary.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 135, 0, 0.5) -} - -.badge-secondary { - color: #fff; - background-color: #6c6c6c -} - -a.badge-secondary:hover, -a.badge-secondary:focus { - color: #fff; - background-color: #535252 -} - -a.badge-secondary:focus, -a.badge-secondary.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(108, 108, 108, 0.5) -} - -.badge-success { - color: #fff; - background-color: #5cb85c -} - -a.badge-success:hover, -a.badge-success:focus { - color: #fff; - background-color: #449d44 -} - -a.badge-success:focus, -a.badge-success.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(92, 184, 92, 0.5) -} - -.badge-info { - color: #212121; - background-color: #5bc0de -} - -a.badge-info:hover, -a.badge-info:focus { - color: #212121; - background-color: #31b0d5 -} - -a.badge-info:focus, -a.badge-info.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(91, 192, 222, 0.5) -} - -.badge-warning { - color: #212121; - background-color: #f0ad4e -} - -a.badge-warning:hover, -a.badge-warning:focus { - color: #212121; - background-color: #ec971f -} - -a.badge-warning:focus, -a.badge-warning.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(240, 173, 78, 0.5) -} - -.badge-danger { - color: #fff; - background-color: #d9534f -} - -a.badge-danger:hover, -a.badge-danger:focus { - color: #fff; - background-color: #c9302c -} - -a.badge-danger:focus, -a.badge-danger.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(217, 83, 79, 0.5) -} - -.badge-light { - color: #212121; - background-color: #f2f2f2 -} - -a.badge-light:hover, -a.badge-light:focus { - color: #212121; - background-color: #d9d8d8 -} - -a.badge-light:focus, -a.badge-light.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(242, 242, 242, 0.5) -} - -.badge-dark { - color: #fff; - background-color: #313131 -} - -a.badge-dark:hover, -a.badge-dark:focus { - color: #fff; - background-color: #181717 -} - -a.badge-dark:focus, -a.badge-dark.focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(49, 49, 49, 0.5) -} - -.jumbotron { - padding: 2rem 1rem; - margin-bottom: 2rem; - background-color: #e9e9e9; - 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: 600 -} - -.alert-dismissible { - padding-right: 4rem -} - -.alert-dismissible .close { - position: absolute; - top: 0; - right: 0; - padding: .75rem 1.25rem; - color: inherit -} - -.alert-primary { - color: #854600; - background-color: #ffe7cc; - border-color: #ffddb8 -} - -.alert-primary hr { - border-top-color: #ffd19f -} - -.alert-primary .alert-link { - color: #522b00 -} - -.alert-secondary { - color: #383838; - background-color: #e2e2e2; - border-color: #d6d6d6 -} - -.alert-secondary hr { - border-top-color: #c9c9c9 -} - -.alert-secondary .alert-link { - color: #1f1e1e -} - -.alert-success { - color: #306030; - background-color: #def1de; - border-color: #d1ebd1 -} - -.alert-success hr { - border-top-color: #bfe3bf -} - -.alert-success .alert-link { - color: #1f3e1f -} - -.alert-info { - color: #2f6473; - background-color: #def2f8; - border-color: #d1edf6 -} - -.alert-info hr { - border-top-color: #bce5f2 -} - -.alert-info .alert-link { - color: #20454f -} - -.alert-warning { - color: #7d5a29; - background-color: #fcefdc; - border-color: #fbe8cd -} - -.alert-warning hr { - border-top-color: #f9ddb5 -} - -.alert-warning .alert-link { - color: #573e1c -} - -.alert-danger { - color: #712b29; - background-color: #f7dddc; - border-color: #f4cfce -} - -.alert-danger hr { - border-top-color: #efbbb9 -} - -.alert-danger .alert-link { - color: #4c1d1b -} - -.alert-light { - color: #7e7e7e; - background-color: #fcfcfc; - border-color: #fbfbfb -} - -.alert-light hr { - border-top-color: #eee -} - -.alert-light .alert-link { - color: #656464 -} - -.alert-dark { - color: #191919; - background-color: #d6d6d6; - border-color: #c5c5c5 -} - -.alert-dark hr { - border-top-color: #b8b8b8 -} - -.alert-dark .alert-link { - color: #000 -} - -@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: #e9e9e9; - border-radius: .25rem -} - -.progress-bar { - display: flex; - flex-direction: column; - justify-content: center; - overflow: hidden; - color: #fff; - text-align: center; - white-space: nowrap; - background-color: #ff8700; - transition: width 0.6s ease -} - -@media (prefers-reduced-motion: reduce) { - .progress-bar { - transition: none - } -} - -.progress-bar-striped { - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-size: 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: #494949; - text-align: inherit -} - -.list-group-item-action:hover, -.list-group-item-action:focus { - z-index: 1; - color: #494949; - text-decoration: none; - background-color: #f2f2f2 -} - -.list-group-item-action:active { - color: #212121; - background-color: #e9e9e9 -} - -.list-group-item { - position: relative; - display: block; - padding: .75rem 1.25rem; - background-color: #fff; - border: 1px solid rgba(0, 0, 0, 0.125) -} - -.list-group-item:first-child { - border-top-left-radius: .25rem; - border-top-right-radius: .25rem -} - -.list-group-item:last-child { - border-bottom-right-radius: .25rem; - border-bottom-left-radius: .25rem -} - -.list-group-item.disabled, -.list-group-item:disabled { - color: #6c6c6c; - pointer-events: none; - background-color: #fff -} - -.list-group-item.active { - z-index: 2; - color: #fff; - background-color: #ff8700; - border-color: #ff8700 -} - -.list-group-item+.list-group-item { - border-top-width: 0 -} - -.list-group-item+.list-group-item.active { - margin-top: -1px; - border-top-width: 1px -} - -.list-group-horizontal { - flex-direction: row -} - -.list-group-horizontal .list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 -} - -.list-group-horizontal .list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 -} - -.list-group-horizontal .list-group-item.active { - margin-top: 0 -} - -.list-group-horizontal .list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 -} - -.list-group-horizontal .list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px -} - -@media (min-width: 576px) { - .list-group-horizontal-sm { - flex-direction: row - } - - .list-group-horizontal-sm .list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-sm .list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-sm .list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-sm .list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-sm .list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width: 768px) { - .list-group-horizontal-md { - flex-direction: row - } - - .list-group-horizontal-md .list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-md .list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-md .list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-md .list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-md .list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width: 992px) { - .list-group-horizontal-lg { - flex-direction: row - } - - .list-group-horizontal-lg .list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-lg .list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-lg .list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-lg .list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-lg .list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width: 1200px) { - .list-group-horizontal-xl { - flex-direction: row - } - - .list-group-horizontal-xl .list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-xl .list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-xl .list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-xl .list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-xl .list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -.list-group-flush .list-group-item { - border-right-width: 0; - border-left-width: 0; - border-radius: 0 -} - -.list-group-flush .list-group-item:first-child { - border-top-width: 0 -} - -.list-group-flush:last-child .list-group-item:last-child { - border-bottom-width: 0 -} - -.list-group-item-primary { - color: #854600; - background-color: #ffddb8 -} - -.list-group-item-primary.list-group-item-action:hover, -.list-group-item-primary.list-group-item-action:focus { - color: #854600; - background-color: #ffd19f -} - -.list-group-item-primary.list-group-item-action.active { - color: #fff; - background-color: #854600; - border-color: #854600 -} - -.list-group-item-secondary { - color: #383838; - background-color: #d6d6d6 -} - -.list-group-item-secondary.list-group-item-action:hover, -.list-group-item-secondary.list-group-item-action:focus { - color: #383838; - background-color: #c9c9c9 -} - -.list-group-item-secondary.list-group-item-action.active { - color: #fff; - background-color: #383838; - border-color: #383838 -} - -.list-group-item-success { - color: #306030; - background-color: #d1ebd1 -} - -.list-group-item-success.list-group-item-action:hover, -.list-group-item-success.list-group-item-action:focus { - color: #306030; - background-color: #bfe3bf -} - -.list-group-item-success.list-group-item-action.active { - color: #fff; - background-color: #306030; - border-color: #306030 -} - -.list-group-item-info { - color: #2f6473; - background-color: #d1edf6 -} - -.list-group-item-info.list-group-item-action:hover, -.list-group-item-info.list-group-item-action:focus { - color: #2f6473; - background-color: #bce5f2 -} - -.list-group-item-info.list-group-item-action.active { - color: #fff; - background-color: #2f6473; - border-color: #2f6473 -} - -.list-group-item-warning { - color: #7d5a29; - background-color: #fbe8cd -} - -.list-group-item-warning.list-group-item-action:hover, -.list-group-item-warning.list-group-item-action:focus { - color: #7d5a29; - background-color: #f9ddb5 -} - -.list-group-item-warning.list-group-item-action.active { - color: #fff; - background-color: #7d5a29; - border-color: #7d5a29 -} - -.list-group-item-danger { - color: #712b29; - background-color: #f4cfce -} - -.list-group-item-danger.list-group-item-action:hover, -.list-group-item-danger.list-group-item-action:focus { - color: #712b29; - background-color: #efbbb9 -} - -.list-group-item-danger.list-group-item-action.active { - color: #fff; - background-color: #712b29; - border-color: #712b29 -} - -.list-group-item-light { - color: #7e7e7e; - background-color: #fbfbfb -} - -.list-group-item-light.list-group-item-action:hover, -.list-group-item-light.list-group-item-action:focus { - color: #7e7e7e; - background-color: #eee -} - -.list-group-item-light.list-group-item-action.active { - color: #fff; - background-color: #7e7e7e; - border-color: #7e7e7e -} - -.list-group-item-dark { - color: #191919; - background-color: #c5c5c5 -} - -.list-group-item-dark.list-group-item-action:hover, -.list-group-item-dark.list-group-item-action:focus { - color: #191919; - background-color: #b8b8b8 -} - -.list-group-item-dark.list-group-item-action.active { - color: #fff; - background-color: #191919; - border-color: #191919 -} - -.close { - float: right; - font-size: 1.5rem; - font-weight: 600; - 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):hover, -.close:not(:disabled):not(.disabled):focus { - 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, 0.85); - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.1); - box-shadow: 0 0.25rem 0.75rem rgba(0, 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: #6c6c6c; - background-color: rgba(255, 255, 255, 0.85); - background-clip: padding-box; - border-bottom: 1px solid rgba(0, 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 0.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.modal-static .modal-dialog { - transform: scale(1.02) -} - -.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-header, -.modal-dialog-scrollable .modal-footer { - 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, 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 #dedede; - border-top-left-radius: calc(.3rem - 1px); - border-top-right-radius: calc(.3rem - 1px) -} - -.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; - flex-wrap: wrap; - align-items: center; - justify-content: flex-end; - padding: .75rem; - border-top: 1px solid #dedede; - border-bottom-right-radius: calc(.3rem - 1px); - border-bottom-left-radius: calc(.3rem - 1px) -} - -.modal-footer>* { - margin: .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: "Source Sans Pro", sans-serif; - 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-top, -.bs-tooltip-auto[x-placement^="top"] { - padding: .4rem 0 -} - -.bs-tooltip-top .arrow, -.bs-tooltip-auto[x-placement^="top"] .arrow { - bottom: 0 -} - -.bs-tooltip-top .arrow::before, -.bs-tooltip-auto[x-placement^="top"] .arrow::before { - top: 0; - border-width: .4rem .4rem 0; - border-top-color: #000 -} - -.bs-tooltip-right, -.bs-tooltip-auto[x-placement^="right"] { - padding: 0 .4rem -} - -.bs-tooltip-right .arrow, -.bs-tooltip-auto[x-placement^="right"] .arrow { - left: 0; - width: .4rem; - height: .8rem -} - -.bs-tooltip-right .arrow::before, -.bs-tooltip-auto[x-placement^="right"] .arrow::before { - right: 0; - border-width: .4rem .4rem .4rem 0; - border-right-color: #000 -} - -.bs-tooltip-bottom, -.bs-tooltip-auto[x-placement^="bottom"] { - padding: .4rem 0 -} - -.bs-tooltip-bottom .arrow, -.bs-tooltip-auto[x-placement^="bottom"] .arrow { - top: 0 -} - -.bs-tooltip-bottom .arrow::before, -.bs-tooltip-auto[x-placement^="bottom"] .arrow::before { - bottom: 0; - border-width: 0 .4rem .4rem; - border-bottom-color: #000 -} - -.bs-tooltip-left, -.bs-tooltip-auto[x-placement^="left"] { - padding: 0 .4rem -} - -.bs-tooltip-left .arrow, -.bs-tooltip-auto[x-placement^="left"] .arrow { - right: 0; - width: .4rem; - height: .8rem -} - -.bs-tooltip-left .arrow::before, -.bs-tooltip-auto[x-placement^="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: "Source Sans Pro", sans-serif; - 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, 0.2); - border-radius: .3rem -} - -.popover .arrow { - position: absolute; - display: block; - width: 1rem; - height: .5rem; - margin: 0 .3rem -} - -.popover .arrow::before, -.popover .arrow::after { - position: absolute; - display: block; - content: ""; - border-color: transparent; - border-style: solid -} - -.bs-popover-top, -.bs-popover-auto[x-placement^="top"] { - margin-bottom: .5rem -} - -.bs-popover-top>.arrow, -.bs-popover-auto[x-placement^="top"]>.arrow { - bottom: calc(-.5rem - 1px) -} - -.bs-popover-top>.arrow::before, -.bs-popover-auto[x-placement^="top"]>.arrow::before { - bottom: 0; - border-width: .5rem .5rem 0; - border-top-color: rgba(0, 0, 0, 0.25) -} - -.bs-popover-top>.arrow::after, -.bs-popover-auto[x-placement^="top"]>.arrow::after { - bottom: 1px; - border-width: .5rem .5rem 0; - border-top-color: #fff -} - -.bs-popover-right, -.bs-popover-auto[x-placement^="right"] { - margin-left: .5rem -} - -.bs-popover-right>.arrow, -.bs-popover-auto[x-placement^="right"]>.arrow { - left: calc(-.5rem - 1px); - width: .5rem; - height: 1rem; - margin: .3rem 0 -} - -.bs-popover-right>.arrow::before, -.bs-popover-auto[x-placement^="right"]>.arrow::before { - left: 0; - border-width: .5rem .5rem .5rem 0; - border-right-color: rgba(0, 0, 0, 0.25) -} - -.bs-popover-right>.arrow::after, -.bs-popover-auto[x-placement^="right"]>.arrow::after { - left: 1px; - border-width: .5rem .5rem .5rem 0; - border-right-color: #fff -} - -.bs-popover-bottom, -.bs-popover-auto[x-placement^="bottom"] { - margin-top: .5rem -} - -.bs-popover-bottom>.arrow, -.bs-popover-auto[x-placement^="bottom"]>.arrow { - top: calc(-.5rem - 1px) -} - -.bs-popover-bottom>.arrow::before, -.bs-popover-auto[x-placement^="bottom"]>.arrow::before { - top: 0; - border-width: 0 .5rem .5rem .5rem; - border-bottom-color: rgba(0, 0, 0, 0.25) -} - -.bs-popover-bottom>.arrow::after, -.bs-popover-auto[x-placement^="bottom"]>.arrow::after { - top: 1px; - border-width: 0 .5rem .5rem .5rem; - border-bottom-color: #fff -} - -.bs-popover-bottom .popover-header::before, -.bs-popover-auto[x-placement^="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-left, -.bs-popover-auto[x-placement^="left"] { - margin-right: .5rem -} - -.bs-popover-left>.arrow, -.bs-popover-auto[x-placement^="left"]>.arrow { - right: calc(-.5rem - 1px); - width: .5rem; - height: 1rem; - margin: .3rem 0 -} - -.bs-popover-left>.arrow::before, -.bs-popover-auto[x-placement^="left"]>.arrow::before { - right: 0; - border-width: .5rem 0 .5rem .5rem; - border-left-color: rgba(0, 0, 0, 0.25) -} - -.bs-popover-left>.arrow::after, -.bs-popover-auto[x-placement^="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: #212121 -} - -.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.active, -.carousel-item-next, -.carousel-item-prev { - display: block -} - -.carousel-item-next:not(.carousel-item-left), -.active.carousel-item-right { - transform: translateX(100%) -} - -.carousel-item-prev:not(.carousel-item-right), -.active.carousel-item-left { - transform: translateX(-100%) -} - -.carousel-fade .carousel-item { - opacity: 0; - transition-property: opacity; - transform: none -} - -.carousel-fade .carousel-item.active, -.carousel-fade .carousel-item-next.carousel-item-left, -.carousel-fade .carousel-item-prev.carousel-item-right { - z-index: 1; - opacity: 1 -} - -.carousel-fade .active.carousel-item-left, -.carousel-fade .active.carousel-item-right { - z-index: 0; - opacity: 0; - transition: opacity 0s .6s -} - -@media (prefers-reduced-motion: reduce) { - - .carousel-fade .active.carousel-item-left, - .carousel-fade .active.carousel-item-right { - transition: none - } -} - -.carousel-control-prev, -.carousel-control-next { - 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 0.15s ease -} - -@media (prefers-reduced-motion: reduce) { - - .carousel-control-prev, - .carousel-control-next { - transition: none - } -} - -.carousel-control-prev:hover, -.carousel-control-prev:focus, -.carousel-control-next:hover, -.carousel-control-next:focus { - color: #fff; - text-decoration: none; - outline: 0; - opacity: .9 -} - -.carousel-control-prev { - left: 0 -} - -.carousel-control-next { - right: 0 -} - -.carousel-control-prev-icon, -.carousel-control-next-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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-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 0.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: #ff8700 !important -} - -a.bg-primary:hover, -a.bg-primary:focus, -button.bg-primary:hover, -button.bg-primary:focus { - background-color: #cc6c00 !important -} - -.bg-secondary { - background-color: #6c6c6c !important -} - -a.bg-secondary:hover, -a.bg-secondary:focus, -button.bg-secondary:hover, -button.bg-secondary:focus { - background-color: #535252 !important -} - -.bg-success { - background-color: #5cb85c !important -} - -a.bg-success:hover, -a.bg-success:focus, -button.bg-success:hover, -button.bg-success:focus { - background-color: #449d44 !important -} - -.bg-info { - background-color: #5bc0de !important -} - -a.bg-info:hover, -a.bg-info:focus, -button.bg-info:hover, -button.bg-info:focus { - background-color: #31b0d5 !important -} - -.bg-warning { - background-color: #f0ad4e !important -} - -a.bg-warning:hover, -a.bg-warning:focus, -button.bg-warning:hover, -button.bg-warning:focus { - background-color: #ec971f !important -} - -.bg-danger { - background-color: #d9534f !important -} - -a.bg-danger:hover, -a.bg-danger:focus, -button.bg-danger:hover, -button.bg-danger:focus { - background-color: #c9302c !important -} - -.bg-light { - background-color: #f2f2f2 !important -} - -a.bg-light:hover, -a.bg-light:focus, -button.bg-light:hover, -button.bg-light:focus { - background-color: #d9d8d8 !important -} - -.bg-dark { - background-color: #313131 !important -} - -a.bg-dark:hover, -a.bg-dark:focus, -button.bg-dark:hover, -button.bg-dark:focus { - background-color: #181717 !important -} - -.bg-white { - background-color: #fff !important -} - -.bg-transparent { - background-color: transparent !important -} - -.border, -.with-border { - border: 1px solid #dedede !important -} - -.border-top { - border-top: 1px solid #dedede !important -} - -.border-right { - border-right: 1px solid #dedede !important -} - -.border-bottom { - border-bottom: 1px solid #dedede !important -} - -.border-left { - border-left: 1px solid #dedede !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: #ff8700 !important -} - -.border-secondary { - border-color: #6c6c6c !important -} - -.border-success { - border-color: #5cb85c !important -} - -.border-info { - border-color: #5bc0de !important -} - -.border-warning { - border-color: #f0ad4e !important -} - -.border-danger { - border-color: #d9534f !important -} - -.border-light { - border-color: #f2f2f2 !important -} - -.border-dark { - border-color: #313131 !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 iframe, -.embed-responsive embed, -.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.8571428571% -} - -.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; - margin: -1px; - 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, -.with-shadow { - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2) !important -} - -.shadow { - box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important -} - -.shadow-lg { - box-shadow: 0 1rem 3rem rgba(0, 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: "Source Code Pro", 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, -.align-center, -.centered { - 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: 600 !important -} - -.font-weight-bolder { - font-weight: bolder !important -} - -.font-italic { - font-style: italic !important -} - -.text-white { - color: #fff !important -} - -.text-primary { - color: #ff8700 !important -} - -a.text-primary:hover, -a.text-primary:focus { - color: #b35f00 !important -} - -.text-secondary { - color: #6c6c6c !important -} - -a.text-secondary:hover, -a.text-secondary:focus { - color: #464646 !important -} - -.text-success { - color: #5cb85c !important -} - -a.text-success:hover, -a.text-success:focus { - color: #3d8b3d !important -} - -.text-info { - color: #5bc0de !important -} - -a.text-info:hover, -a.text-info:focus { - color: #28a1c5 !important -} - -.text-warning { - color: #f0ad4e !important -} - -a.text-warning:hover, -a.text-warning:focus { - color: #df8a13 !important -} - -.text-danger { - color: #d9534f !important -} - -a.text-danger:hover, -a.text-danger:focus { - color: #b52b27 !important -} - -.text-light { - color: #f2f2f2 !important -} - -a.text-light:hover, -a.text-light:focus { - color: #ccc !important -} - -.text-dark { - color: #313131 !important -} - -a.text-dark:hover, -a.text-dark:focus { - color: #0b0b0b !important -} - -.text-body { - color: #212121 !important -} - -.text-muted { - color: #6c6c6c !important -} - -.text-black-50 { - color: rgba(0, 0, 0, 0.5) !important -} - -.text-white-50 { - color: rgba(255, 255, 255, 0.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 { - - *, - *::before, - *::after { - text-shadow: none !important; - box-shadow: none !important - } - - a:not(.btn):not(.toc-toggle) { - text-decoration: underline - } - - abbr[title]::after { - content: " ("attr(title) ")" - } - - pre { - white-space: pre-wrap !important - } - - pre, - blockquote { - border: 1px solid #ababab; - page-break-inside: avoid - } - - thead { - display: table-header-group - } - - tr, - img { - page-break-inside: avoid - } - - p, - h2, - h3 { - 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, - table.docutils:not(.field-list) { - border-collapse: collapse !important - } - - .table td, - table.docutils:not(.field-list) td, - .table th, - table.docutils:not(.field-list) th { - background-color: #fff !important - } - - .table-bordered th, - table.docutils:not(.field-list) th, - .table-bordered td, - table.docutils:not(.field-list) td { - border: 1px solid #dedede !important - } - - .table-dark { - color: inherit - } - - .table-dark th, - .table-dark td, - .table-dark thead th, - .table-dark tbody+tbody { - border-color: #dedede - } - - .table .thead-dark th, - table.docutils:not(.field-list) .thead-dark th { - color: inherit; - border-color: #dedede - } -} - -.page { - display: flex; - flex-direction: column; - min-height: 100vh -} - -.page-topbar { - position: relative; - flex-grow: 0; - flex-shrink: 0 -} - -.page-header { - position: relative; - z-index: 1; - flex-grow: 0; - flex-shrink: 0; - background: #ffffff; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2) -} - -.page-header-inner { - max-width: 100%; - width: 1140px; - margin: 0 auto; - padding: 0 20px -} - -.page-main { - display: flex; - flex-grow: 1 -} - -.page-main-inner { - display: flex; - flex-flow: wrap column; - max-width: 100%; - width: 1140px; - padding: 0 20px; - margin: 0 auto; - position: relative -} - -@media (min-width: 992px) { - .page-main-inner { - flex-flow: nowrap row - } -} - -.page-main-navigation { - flex-grow: 0; - margin-left: -20px; - margin-right: -20px; - padding: 20px; - border-bottom: 1px solid rgba(0, 0, 0, 0.15) -} - -@media (min-width: 992px) { - .page-main-navigation { - padding: 2rem 0; - flex-shrink: 0; - width: 15rem; - margin: 0; - margin-right: 40px; - padding-right: 20px; - border-bottom: none; - border-right: 1px solid rgba(0, 0, 0, 0.15) - } -} - -.page-main-content { - padding-top: 2rem; - padding-bottom: 2rem; - width: 100%; - min-width: 0; - flex-grow: 1 -} - -@media (min-width: 768px) { - .footer-main { - margin: -20px; - display: flex; - flex-wrap: wrap; - justify-content: space-between - } - - .footer-menu, - .footer-contact { - padding: 20px - } -} - -.footer-menu-group:last-child .footer-menu-group-headline { - margin: 0 -} - -.footer-menu-group-headline { - margin-top: 0; - font-size: 1em -} - -.footer-menu-group-list { - display: none; - list-style: none; - padding: 0 -} - -.footer-menu-group-list li { - margin-top: .25em -} - -.footer-menu-group-list-item-link { - display: flex -} - -.footer-menu-group-list-item-icon { - color: #ff8700; - flex-shrink: 0; - margin-right: .5em; - height: 16px; - width: 16px; - margin-top: .2em -} - -.footer-menu-group-list-item-icon svg, -.footer-menu-group-list-item-icon img { - display: block; - height: 100%; - width: 100% -} - -@media (min-width: 768px) { - .footer-menu { - display: flex - } - - .footer-menu-group { - margin-right: 2.5em - } - - .footer-menu-group:last-child { - margin-right: 0 - } - - .footer-menu-group-headline { - opacity: .75; - margin-bottom: .5em !important - } - - .footer-menu-group-headline:hover { - opacity: 1 - } - - .footer-menu-group-list { - display: block; - margin: 0 - } -} - -.footer-simplemenu { - text-align: center; - list-style: none; - padding-left: 0 -} - -@media (min-width: 576px) { - .footer-simplemenu { - margin-left: -.5em; - margin-right: -.5em - } - - .footer-simplemenu>li { - display: inline-block; - padding-left: .5em; - padding-right: .5em - } -} - -.footer-simplemenu .active a { - font-weight: bold -} - -.footer-meta { - text-align: center -} - -.footer-meta-copyright { - margin-bottom: .5em -} - -.footer-meta-navigation { - list-style: none; - padding: 0; - margin-bottom: 0 -} - -.footer-meta-navigation a { - color: inherit; - display: block -} - -.footer-meta-navigation li { - display: inline-block; - margin-left: .5em; - margin-right: .5em -} - -@media (min-width: 576px) { - .footer-meta-copyright { - display: inline-block; - margin-bottom: 0 - } - - .footer-meta-navigation { - display: inline-block - } - - .footer-meta-navigation li { - display: inline-block; - margin-right: 0 - } -} - -.logo { - display: flex; - height: 70px; - align-items: center -} - -.logo-image { - display: block; - max-width: 100px; - height: auto -} - -.frame-container { - position: relative; - width: 100%; - padding-right: 20px; - padding-left: 20px; - margin-right: auto; - margin-left: auto -} - -@media (min-width: 576px) { - .frame-container { - max-width: 540px - } -} - -@media (min-width: 768px) { - .frame-container { - max-width: 720px - } -} - -@media (min-width: 992px) { - .frame-container { - max-width: 960px - } -} - -@media (min-width: 1200px) { - .frame-container { - max-width: 1140px - } -} - -.frame { - position: relative; - padding-top: 2rem; - padding-bottom: 2rem -} - -@media (min-width: 576px) { - .frame { - padding-top: 2.5rem; - padding-bottom: 2.5rem - } -} - -@media (min-width: 768px) { - .frame { - padding-top: 3rem; - padding-bottom: 3rem - } -} - -@media (min-width: 992px) { - .frame { - padding-top: 3.5rem; - padding-bottom: 3.5rem - } -} - -@media (min-width: 1200px) { - .frame { - padding-top: 3.5rem; - padding-bottom: 3.5rem - } -} - -.frame>*:last-child { - margin-bottom: 0 -} - -.frame-inner>*:last-child { - margin-bottom: 0 -} - -.frame-ruler-before { - border-top: 1px solid rgba(0, 0, 0, 0.125); - margin-top: 0 -} - -.frame-ruler-after { - border-bottom: 1px solid rgba(0, 0, 0, 0.125); - margin-bottom: 2rem -} - -@media (min-width: 576px) { - .frame-ruler-after { - margin-bottom: 2.5rem - } -} - -@media (min-width: 768px) { - .frame-ruler-after { - margin-bottom: 3rem - } -} - -@media (min-width: 992px) { - .frame-ruler-after { - margin-bottom: 3.5rem - } -} - -@media (min-width: 1200px) { - .frame-ruler-after { - margin-bottom: 3.5rem - } -} - -.frame-indent .frame-inner { - margin-left: 0%; - margin-right: 0% -} - -@media (min-width: 576px) { - .frame-indent .frame-inner { - margin-left: 4%; - margin-right: 4% - } -} - -@media (min-width: 768px) { - .frame-indent .frame-inner { - margin-left: 8%; - margin-right: 8% - } -} - -@media (min-width: 992px) { - .frame-indent .frame-inner { - margin-left: 12%; - margin-right: 12% - } -} - -@media (min-width: 1200px) { - .frame-indent .frame-inner { - margin-left: 16%; - margin-right: 16% - } -} - -.frame-indent-left .frame-inner { - margin-left: 0% -} - -@media (min-width: 576px) { - .frame-indent-left .frame-inner { - margin-left: 8% - } -} - -@media (min-width: 768px) { - .frame-indent-left .frame-inner { - margin-left: 16% - } -} - -@media (min-width: 992px) { - .frame-indent-left .frame-inner { - margin-left: 24% - } -} - -@media (min-width: 1200px) { - .frame-indent-left .frame-inner { - margin-left: 32% - } -} - -.frame-indent-right .frame-inner { - margin-right: 0% -} - -@media (min-width: 576px) { - .frame-indent-right .frame-inner { - margin-right: 8% - } -} - -@media (min-width: 768px) { - .frame-indent-right .frame-inner { - margin-right: 16% - } -} - -@media (min-width: 992px) { - .frame-indent-right .frame-inner { - margin-right: 24% - } -} - -@media (min-width: 1200px) { - .frame-indent-right .frame-inner { - margin-right: 32% - } -} - -.frame-small { - padding-top: .5rem; - padding-bottom: .5rem -} - -@media (min-width: 576px) { - .frame-small { - padding-top: 1rem; - padding-bottom: 1rem - } -} - -.container .frame-has-backgroundimage, -.container .frame-background-primary, -.container .frame-background-secondary, -.container .frame-background-light, -.container .frame-background-dark { - padding-left: 2rem; - padding-right: 2rem -} - -@media (min-width: 576px) { - - .container .frame-has-backgroundimage, - .container .frame-background-primary, - .container .frame-background-secondary, - .container .frame-background-light, - .container .frame-background-dark { - padding-left: 2.5rem; - padding-right: 2.5rem - } -} - -@media (min-width: 768px) { - - .container .frame-has-backgroundimage, - .container .frame-background-primary, - .container .frame-background-secondary, - .container .frame-background-light, - .container .frame-background-dark { - padding-left: 3rem; - padding-right: 3rem - } -} - -@media (min-width: 992px) { - - .container .frame-has-backgroundimage, - .container .frame-background-primary, - .container .frame-background-secondary, - .container .frame-background-light, - .container .frame-background-dark { - padding-left: 3.5rem; - padding-right: 3.5rem - } -} - -@media (min-width: 1200px) { - - .container .frame-has-backgroundimage, - .container .frame-background-primary, - .container .frame-background-secondary, - .container .frame-background-light, - .container .frame-background-dark { - padding-left: 3.5rem; - padding-right: 3.5rem - } -} - -.frame-collapsible, -.frame-background-none:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-none:not(.frame-ruler-before):not(.frame-has-backgroundimage), -.frame-background-primary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-primary:not(.frame-ruler-before):not(.frame-has-backgroundimage), -.frame-background-secondary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-secondary:not(.frame-ruler-before):not(.frame-has-backgroundimage), -.frame-background-light:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-light:not(.frame-ruler-before):not(.frame-has-backgroundimage), -.frame-background-dark:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-dark:not(.frame-ruler-before):not(.frame-has-backgroundimage) { - margin-top: -2rem -} - -@media (min-width: 576px) { - - .frame-collapsible, - .frame-background-none:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-none:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-primary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-primary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-secondary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-secondary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-light:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-light:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-dark:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-dark:not(.frame-ruler-before):not(.frame-has-backgroundimage) { - margin-top: -2.5rem - } -} - -@media (min-width: 768px) { - - .frame-collapsible, - .frame-background-none:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-none:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-primary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-primary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-secondary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-secondary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-light:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-light:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-dark:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-dark:not(.frame-ruler-before):not(.frame-has-backgroundimage) { - margin-top: -3rem - } -} - -@media (min-width: 992px) { - - .frame-collapsible, - .frame-background-none:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-none:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-primary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-primary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-secondary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-secondary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-light:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-light:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-dark:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-dark:not(.frame-ruler-before):not(.frame-has-backgroundimage) { - margin-top: -3.5rem - } -} - -@media (min-width: 1200px) { - - .frame-collapsible, - .frame-background-none:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-none:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-primary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-primary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-secondary:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-secondary:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-light:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-light:not(.frame-ruler-before):not(.frame-has-backgroundimage), - .frame-background-dark:not(.frame-ruler-after):not(.frame-has-backgroundimage)+.frame-background-dark:not(.frame-ruler-before):not(.frame-has-backgroundimage) { - margin-top: -3.5rem - } -} - -.frame-background-primary { - color: #fff; - background-color: #ff8700 -} - -.frame-background-primary a:not(.btn):not(.toc-toggle) { - color: #fff -} - -.frame-background-primary a:not(.btn):not(.toc-toggle):hover { - color: #d9d9d9 -} - -.frame-background-secondary { - color: #fff; - background-color: #6c6c6c -} - -.frame-background-secondary a:not(.btn):not(.toc-toggle) { - color: #fff -} - -.frame-background-secondary a:not(.btn):not(.toc-toggle):hover { - color: #d9d9d9 -} - -.frame-background-light { - color: #212121; - background-color: #f2f2f2 -} - -.frame-background-light a:not(.btn):not(.toc-toggle) { - color: #ff8700 -} - -.frame-background-light a:not(.btn):not(.toc-toggle):hover { - color: #b35f00 -} - -.frame-background-dark { - color: #fff; - background-color: #313131 -} - -.frame-background-dark a:not(.btn):not(.toc-toggle) { - color: #ff8700 -} - -.frame-background-dark a:not(.btn):not(.toc-toggle):hover { - color: #b35f00 -} - -.frame-backgroundimage-container { - overflow: hidden -} - -.frame-backgroundimage-container, -.frame-backgroundimage { - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; - background-position: center; - background-size: cover -} - -.frame-backgroundimage-fade { - opacity: .125 -} - -.frame-backgroundimage-parallax { - background-attachment: fixed; - background-repeat: no-repeat -} - -@media (hover: none) { - .frame-backgroundimage-parallax { - background-attachment: initial - } -} - -.frame-backgroundimage-blur { - filter: blur(10px); - width: calc(100% + 40px); - height: calc(100% + 40px); - top: -20px; - left: -20px -} - -.frame-backgroundimage-grayscale { - filter: grayscale(1) -} - -.frame-backgroundimage-sepia { - filter: sepia(1) -} - -.frame-header *:last-child { - margin-bottom: 1rem -} - -.frame-type-header .frame-header *:last-child { - margin-bottom: 0 -} - -.breadcrumb-bar { - margin-bottom: 1rem; - border-bottom: 1px solid rgba(0, 0, 0, 0.15); - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap -} - -.breadcrumb-bar .breadcrumb { - background-color: transparent; - margin-bottom: 1rem; - padding: 0 -} - -.breadcrumb-bar .breadcrumb-additions { - margin-bottom: 1rem; - display: none -} - -@media (min-width: 768px) { - .breadcrumb-bar .breadcrumb-additions { - display: block - } -} - -.btn, -.toc-toggle { - display: inline-flex; - align-items: center; - text-align: left -} - -.btn-icon:first-child { - margin-right: .5rem -} - -.btn-icon:last-child { - margin-left: .5rem -} - -.toc-checkbox { - display: none -} - -.toc-collapse { - display: none -} - -@media (min-width: 992px) { - .toc-collapse { - display: block - } -} - -.toc-checkbox:checked~.toc-collapse { - display: block -} - -.toc-toggle { - margin: 0 -} - -@media (min-width: 992px) { - .toc-toggle { - display: none - } -} - -.toc-header { - display: flex; - justify-content: space-between -} - -.toc { - margin: 1rem 0; - display: block -} - -.toc .caption { - font-weight: bold; - margin: 0 -} - -.toc a { - position: relative; - display: block; - color: inherit; - line-height: 1.25; - padding: .25rem 0; - padding-right: 1.5em; - text-decoration: none -} - -.toc ul { - padding-left: 1rem; - list-style-type: none -} - -.toc li { - border-radius: .25rem; - overflow: hidden -} - -.toc .toctree-expand { - position: absolute; - display: block; - top: .875rem; - right: 0; - transform: translate(0, -50%); - height: 1em; - width: 1em; - background-color: #f2f2f2; - border-radius: .25rem -} - -.toc .toctree-expand:after, -.toc .toctree-expand:before { - position: absolute; - content: ''; - top: 50%; - left: 50% -} - -.toc .toctree-expand:after { - width: 10px; - height: 0; - border-top: 2px solid; - transform: translate(-50%, -50%) -} - -.toc .toctree-expand:before { - width: 0; - height: 10px; - border-left: 2px solid; - transform: translate(-50%, -50%) -} - -.toc .current>a { - color: #ff8700 -} - -.toc .current>a>.toctree-expand { - background-color: #ff8700; - color: #fff -} - -.toc .current>a>.toctree-expand:before { - display: none -} - -.toc>ul { - padding-left: 0 -} - -.toc>ul .current>ul { - display: block !important -} - -.toc>ul>li ul { - display: none -} - -.toc>ul:not(:last-child) { - padding-bottom: 1rem; - border-bottom: 1px solid rgba(0, 0, 0, 0.15) -} - -.toc-title-project { - display: block; - font-size: 1.5em; - line-height: 1.25 -} - -.toc-search { - margin-top: 1rem; - margin-bottom: 2rem -} - -.toc-backref { - color: inherit -} - -.toc-backref:hover { - color: inherit; - text-decoration: none -} - -.toc-version { - cursor: pointer; - display: flex; - align-items: center -} - -.toc-version:after { - content: ''; - display: inline-block; - margin-left: .25em; - vertical-align: middle; - border: .25em solid transparent; - border-bottom: none; - border-top-color: inherit -} - -.toc-version-number { - margin-left: .25em; - font-weight: bold -} - -.toc-version-toggle { - margin-left: auto -} - -.toc-version-wrapper { - margin-top: .5rem; - border-radius: .25rem -} - -.toc-version-options { - display: none; - margin-top: .5rem; - margin-bottom: 0; - border-radius: .25rem; - overflow: hidden; - color: #212121; - background-color: #f2f2f2 -} - -.toc-version-options a { - padding: .375rem .75rem; - display: block; - color: inherit -} - -.toc-version-options a:hover { - text-decoration: none; - color: #fff; - background-color: #ff8700 -} - -.toc-version-options p, -.toc-version-options dl, -.toc-version-options dd { - display: block; - margin: 0; - padding: 0 -} - -.toc-version-options p { - padding: .375rem .75rem -} - -.toc-version-wrapper-active .toc-version-options { - display: block -} - -.toc-version-wrapper-active .toc-version:after { - border: .25em solid transparent; - border-top: none; - border-bottom-color: inherit -} - -div[class^='highlight-'] { - overflow-x: auto; - margin-bottom: 1rem -} - -div[class^='highlight-'] pre { - margin: 0; - display: block; - overflow: auto -} - -.linenodiv pre, -.highlight pre { - color: #eff; - padding: 1rem; - border-radius: .25rem; - background-color: #212121 -} - -.linenodiv pre { - background-color: #2e2e2e; - border-right: 1px solid #3b3a3a; - border-top-right-radius: 0; - border-bottom-right-radius: 0 -} - -.highlighttable { - width: 100% -} - -.highlighttable td { - padding: 0 -} - -.highlighttable td.code { - width: 100% -} - -.highlighttable .highlight pre { - border-top-left-radius: 0; - border-bottom-left-radius: 0 -} - -.hll { - background-color: #314549 -} - -.c { - color: #eff -} - -.c1 { - color: #eff -} - -.cm { - color: #eff -} - -.cp { - color: #eff -} - -.cs { - color: #eff -} - -.err { - color: #f07178 -} - -.k { - color: #c792ea -} - -.kc { - color: #c792ea -} - -.kd { - color: #c792ea -} - -.kn { - color: #89ddff -} - -.kp { - color: #c792ea -} - -.kr { - color: #c792ea -} - -.kt { - color: #ffcb6b -} - -.l { - color: #f78c6c -} - -.il { - color: #f78c6c -} - -.ld { - color: #f07178 -} - -.m { - color: #ffcb6b -} - -.mf { - color: #ffcb6b -} - -.mh { - color: #ffcb6b -} - -.mi { - color: #ffcb6b -} - -.mo { - color: #ffcb6b -} - -.s { - color: #82aaff -} - -.s1 { - color: #82aaff -} - -.s2 { - color: #82aaff -} - -.sb { - color: #82aaff -} - -.sc { - color: #82aaff -} - -.sd { - color: #b2ccd6 -} - -.se { - color: #f78c6c -} - -.sh { - color: #82aaff -} - -.si { - color: #f78c6c -} - -.sr { - color: #82aaff -} - -.ss { - color: #82aaff -} - -.sx { - color: #82aaff -} - -.n { - color: #fff -} - -.na { - color: #c3e88d -} - -.nb { - color: #fff -} - -.nc { - color: #ffcb6b -} - -.nd { - color: #89ddff -} - -.ne { - color: #f07178 -} - -.nf { - color: #c3e88d -} - -.ni { - color: #fff -} - -.nl { - color: #fff -} - -.nn { - color: #ffcb6b -} - -.no { - color: #f07178 -} - -.nt { - color: #89ddff -} - -.nv { - color: #f07178 -} - -.nx { - color: #c3e88d -} - -.py { - color: #fff -} - -.bp { - color: #fff -} - -.vc { - color: #f07178 -} - -.vg { - color: #f07178 -} - -.vi { - color: #f07178 -} - -.o { - color: #ff5370 -} - -.p { - color: #eff -} - -.gd { - color: #f07178 -} - -.gh { - color: #fff -} - -.gi { - color: #c3e88d -} - -.gp { - color: #b2ccd6 -} - -.gu { - color: #89ddff -} - -.ow { - color: #89ddff -} - -.w { - color: #fff -} - -.x { - color: #eff -} - -.ge { - font-style: italic -} - -.gh { - font-weight: 600 -} - -.gp { - font-weight: 600 -} - -.gs { - font-weight: 600 -} - -.gu { - font-weight: 600 -} - -.clear-both { - clear: both -} - -.section { - margin-top: 2.5rem; - margin-bottom: 2.5rem -} - -.section::after { - display: block; - clear: both; - content: "" -} - -.headerlink { - position: relative; - font-size: .65em; - visibility: hidden; - top: -.15em -} - -.headerlink:after { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - display: inline-block; - font-style: normal; - font-variant: normal; - font-weight: normal; - line-height: 1; - content: "\f0c1"; - font-family: 'Font Awesome 5 Free'; - font-weight: 900; - margin-left: -.35em -} - -.headerlink:hover { - text-decoration: none -} - -*:hover>.headerlink:after { - visibility: visible -} - -table.docutils:not(.field-list) { - border: 0 -} - -table.docutils.field-list .field-name { - padding-right: 1rem -} - -.table-responsive { - margin-bottom: 1rem -} - -.table-responsive table.docutils { - margin-bottom: 0 -} - -.admonition { - background-color: #e6e6e6; - margin: 1rem 0; - padding: 1rem; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2); - border-radius: .25rem; - overflow: hidden -} - -.admonition *:last-child { - margin-bottom: 0 -} - -.admonition-title { - display: block; - padding: .5rem 1rem; - margin: -1rem; - margin-bottom: 1rem; - color: #fff; - background-color: #313131 -} - -.admonition-title:before { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - display: inline-block; - font-style: normal; - font-variant: normal; - font-weight: normal; - line-height: 1; - content: "\f05a"; - font-family: 'Font Awesome 5 Free'; - font-weight: 900; - margin-right: .5rem -} - -.admonition.hint, -.admonition.note { - background-color: #ebf7fb -} - -.admonition.hint .admonition-title, -.admonition.note .admonition-title { - color: #212121; - background-color: #5bc0de -} - -.admonition.caution, -.admonition.warning, -.admonition.attention { - background-color: #fdf5ea -} - -.admonition.caution .admonition-title, -.admonition.warning .admonition-title, -.admonition.attention .admonition-title { - color: #212121; - background-color: #f0ad4e -} - -.admonition.caution .admonition-title:before, -.admonition.warning .admonition-title:before, -.admonition.attention .admonition-title:before { - content: "\f071" -} - -.admonition.danger, -.admonition.error { - background-color: #faeaea -} - -.admonition.danger .admonition-title, -.admonition.error .admonition-title { - color: #fff; - background-color: #d9534f -} - -.admonition.danger .admonition-title:before, -.admonition.error .admonition-title:before { - content: "\f071" -} - -.admonition.important, -.admonition.seealso, -.admonition.tip { - background-color: #ebf6eb -} - -.admonition.important .admonition-title, -.admonition.seealso .admonition-title, -.admonition.tip .admonition-title { - color: #fff; - background-color: #5cb85c -} - -.bignums, -.bignums-hint, -.bignums-note, -.bignums-caution, -.bignums-warning, -.bignums-attention, -.bignums-important, -.bignums-seealso, -.bignums-tip, -.bignums-danger, -.bignums-error, -.bignums-xxl { - padding: 0; - counter-reset: li-counter -} - -.bignums>li, -.bignums-hint>li, -.bignums-note>li, -.bignums-caution>li, -.bignums-warning>li, -.bignums-attention>li, -.bignums-important>li, -.bignums-seealso>li, -.bignums-tip>li, -.bignums-danger>li, -.bignums-error>li, -.bignums-xxl>li { - list-style: none; - position: relative; - padding: 1rem; - padding-left: 3.875rem; - padding-top: 1.2875rem; - background-color: #e6e6e6; - min-height: 4.3rem; - border-radius: .25rem -} - -.bignums>li>.first, -.bignums-hint>li>.first, -.bignums-note>li>.first, -.bignums-caution>li>.first, -.bignums-warning>li>.first, -.bignums-attention>li>.first, -.bignums-important>li>.first, -.bignums-seealso>li>.first, -.bignums-tip>li>.first, -.bignums-danger>li>.first, -.bignums-error>li>.first, -.bignums-xxl>li>.first { - font-weight: 600; - font-size: 1.15rem -} - -.bignums>li *:last-child, -.bignums-hint>li *:last-child, -.bignums-note>li *:last-child, -.bignums-caution>li *:last-child, -.bignums-warning>li *:last-child, -.bignums-attention>li *:last-child, -.bignums-important>li *:last-child, -.bignums-seealso>li *:last-child, -.bignums-tip>li *:last-child, -.bignums-danger>li *:last-child, -.bignums-error>li *:last-child, -.bignums-xxl>li *:last-child { - margin-bottom: 0 -} - -.bignums>li:before, -.bignums-hint>li:before, -.bignums-note>li:before, -.bignums-caution>li:before, -.bignums-warning>li:before, -.bignums-attention>li:before, -.bignums-important>li:before, -.bignums-seealso>li:before, -.bignums-tip>li:before, -.bignums-danger>li:before, -.bignums-error>li:before, -.bignums-xxl>li:before { - font-size: 1.15rem; - display: block; - position: absolute; - top: 1rem; - left: 1rem; - height: 2em; - width: 2em; - line-height: 2em; - text-align: center; - background-color: #313131; - color: #fff; - border-radius: 50%; - content: counter(li-counter, decimal); - counter-increment: li-counter; - font-weight: 600 -} - -.bignums>li+li, -.bignums-hint>li+li, -.bignums-note>li+li, -.bignums-caution>li+li, -.bignums-warning>li+li, -.bignums-attention>li+li, -.bignums-important>li+li, -.bignums-seealso>li+li, -.bignums-tip>li+li, -.bignums-danger>li+li, -.bignums-error>li+li, -.bignums-xxl>li+li { - margin-top: 1rem -} - -.bignums-hint>li, -.bignums-note>li { - background-color: #ebf7fb -} - -.bignums-hint>li:before, -.bignums-note>li:before { - background-color: #5bc0de; - color: #212121 -} - -.bignums-caution>li, -.bignums-warning>li, -.bignums-attention>li { - background-color: #fdf5ea -} - -.bignums-caution>li:before, -.bignums-warning>li:before, -.bignums-attention>li:before { - background-color: #f0ad4e; - color: #212121 -} - -.bignums-important>li, -.bignums-seealso>li, -.bignums-tip>li { - background-color: #ebf6eb -} - -.bignums-important>li:before, -.bignums-seealso>li:before, -.bignums-tip>li:before { - background-color: #5cb85c; - color: #fff -} - -.bignums-danger>li, -.bignums-error>li { - background-color: #faeaea -} - -.bignums-danger>li:before, -.bignums-error>li:before { - background-color: #d9534f; - color: #fff -} - -.bignums-xxl>li { - padding: 0; - padding-left: 3.75rem; - padding-top: .375rem; - background-color: transparent; - min-height: 3rem -} - -.bignums-xxl>li>.first { - font-size: 1.5rem -} - -.bignums-xxl>li:before { - font-size: 1.5rem; - top: 0; - left: 0 -} - -.bignums-xxl>li+li { - border-top: 1px solid rgba(0, 0, 0, 0.15); - margin-top: 1.375rem; - padding-top: 1.375rem -} - -.bignums-xxl>li+li:before { - top: 1rem -} - -.sidebar { - margin: 0; - margin-bottom: 1rem; - padding: 1rem; - border-radius: .25rem; - overflow: hidden; - background: #e6e6e6; - font-size: .875rem -} - -@media (min-width: 576px) { - .sidebar { - float: right; - width: 18rem; - margin-left: 1rem - } -} - -.sidebar>.sidebar-title { - font-weight: 600; - color: #fff; - background-color: #313131; - padding: .5rem 1rem; - margin: -1rem; - margin-bottom: 1rem -} - -.sidebar img, -.sidebar p, -.sidebar ul, -.sidebar dl { - margin-bottom: .5em -} - -.sidebar>*:last-child { - margin-bottom: 0 -} - -.rst-content h3 { - padding-bottom: .5rem; - border-bottom: 1px solid rgba(0, 0, 0, 0.1) -} - -.rst-content tt, -.rst-content code { - font-family: "Source Code Pro", monospace; - padding: .25em .5em; - font-size: 75%; - border-radius: .25rem; - background-color: #f2f2f2; - border: 1px solid #dfdfdf -} - -.rst-content code.file { - color: #f08 -} - -.rst-content code.html { - color: #70c -} - -.rst-content code.js { - color: #00660e -} - -.rst-content code.method { - color: #0059b3 -} - -.rst-content code.php { - color: #0059b3 -} - -.rst-content code.py { - color: #0080ff -} - -.rst-content code.ts, -.rst-content code.typoscript { - color: #661400 -} - -.rst-content code.yaml { - color: #0f8a75 -} - -.rst-content .literal-block { - background-color: #f2f2f2; - border-radius: .25rem; - padding: 1rem -} - -.rst-content .toctree-wrapper ul li+li, -.rst-content .toctree-wrapper ol li+li, -.rst-content ul.simple li+li, -.rst-content ol.simple li+li { - margin-top: .5rem -} - -@media (min-width: 992px) { - - .rst-content .compact-list>ul.simple li+li, - .rst-content .compact-list>ol.simple li+li, - .rst-content .toctree-wrapper.compact-list ul li+li, - .rst-content .toctree-wrapper.compact-list ol li+li, - .rst-content ul.simple.compact-list li+li, - .rst-content ol.simple.compact-list li+li { - margin-top: 0 - } -} - -.rst-content kbd { - color: #212121; - background-color: #f2f2f2; - border: 1px solid #cbcbcb; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), inset 0 0 0 2px #fff -} - -.rst-content .versionmodified { - background-color: #fdf1e8; - border-radius: 3px; - border: 1px solid #f9d5b9; - color: #661400; - font-style: italic; - margin: 0 3px 0 0; - padding: 0 2px -} - -.rst-content .guilabel { - font-size: 75%; - padding: .25em .5em; - background-color: #c4e8f3; - color: #214550; - border-radius: .25rem -} - -.rst-content img, -.rst-content object { - display: inline-block; - max-width: 100%; - height: auto -} - -.rst-content img.float-left, -.rst-content object.float-left { - margin-right: 1rem; - margin-bottom: 1rem -} - -.rst-content img.float-right, -.rst-content object.float-right { - margin-left: 1rem; - margin-bottom: 1rem -} - -.rst-content .plantuml object { - height: auto !important -} - -.rst-content .figure, -.rst-content .figure>img, -.rst-content .figure>a>img { - display: block -} - -.rst-content .figure .caption, -.rst-content .figure>img .caption, -.rst-content .figure>a>img .caption { - font-size: .875rem -} - -.rst-content blockquote { - position: relative; - padding: 1.25rem 1.25rem; - padding-left: 3.75rem; - border: 1px solid rgba(0, 0, 0, 0.125); - border-radius: .25rem; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2); - background: #fff -} - -.rst-content blockquote:before { - border-top-left-radius: .25rem; - border-bottom-left-radius: .25rem; - text-align: center; - user-select: none; - position: absolute; - top: 0; - left: 0; - font-size: 2.5rem; - height: 100%; - width: 2.5rem; - background-color: rgba(0, 0, 0, 0.03); - content: '❝' -} - -.rst-content blockquote .attribution { - font-size: 92%; - font-style: italic; - text-align: right -} - -.rst-content blockquote>div>*:last-child { - margin-bottom: 0 -} - -.rst-content dl dd { - margin: 0 0 1rem 2rem -} - -.rst-content dl:not(.docutils) { - margin-bottom: 1rem -} - -.rst-content dl:not(.docutils) dt { - display: inline-block; - font-size: 90%; - padding: .25em .5em; - margin-bottom: .5rem; - position: relative; - border-top: solid 3px #5bc0de; - background-color: #ebf7fb; - color: #4592a9 -} - -.rst-content dl:not(.docutils) dl dt { - border-top: 2px solid #b8b8b8; - background-color: #f2f2f2; - color: #212121 -} - -.rst-content dl:not(.docutils) .descname { - background-color: transparent; - border: none; - padding: 0; - font-size: 100% -} - -.rst-content dl:not(.docutils) .optional { - padding: 0 .25em -} - -.rst-content dl:not(.docutils) .headerlink, -.rst-content dl:not(.docutils) .optional { - color: #212121 -} - -.rst-content dl:not(.docutils) .viewcode-link { - padding-left: 1em -} - -.rst-content dl.dl-parameters dt { - border-top: 2px solid #b8b8b8; - background-color: #dfdfdf; - color: #212121; - font-weight: normal; - padding: .5rem 1rem; - margin-left: 2rem -} - -.rst-content dl.dl-parameters dd { - background-color: #f2f2f2; - color: #212121; - padding: 1rem; - margin-left: 2rem -} - -.rst-content dl.dl-parameters dd *:last-child { - margin-bottom: 0 -} - -.rst-content dl.dl-parameters dd p.first .sep { - opacity: .5; - margin: 0 .25em -} - -.rst-content dl.dl-parameters dd p.first .sep:first-child, -.rst-content dl.dl-parameters dd p.first .sep:last-child { - display: none -} - -.rst-content blockquote dl.dl-parameters dt, -.rst-content blockquote dl.dl-parameters dd { - margin-left: 0 -} - -.rst-content .line-block>.line-block { - margin-left: 1.75em -} - -.rst-content div.genindex-jumpbox { - border-top: 1px solid #dddddd; - border-bottom: 1px solid #dddddd; - margin: 1em 0; - padding: .4em -} - -.rst-content div.modindex-jumpbox { - border-top: 1px solid #dddddd; - border-bottom: 1px solid #dddddd; - margin: 1em 0; - padding: .4em -} - -.rst-content table.indextable { - width: 100% -} - -.rst-content table.indextable td { - text-align: left; - vertical-align: top -} - -.rst-content table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none -} - -.rst-content table.indextable>tbody>tr>td>ul { - padding-left: 0 -} - -.rst-content table.indextable tr.pcap { - height: 10px -} - -.rst-content table.indextable tr.cap { - margin-top: 10px; - background-color: transparent -} - -.rst-content .sphinx-tabs { - margin-bottom: 2em -} - -.rst-content .sphinx-tabs:last-child { - margin-bottom: 1em -} - -.rst-content .sphinx-tabs .sphinx-menu .item p { - margin: 0 -} - -.rst-content .sphinx-tabs .sphinx-menu a.item { - color: #212121 !important -} - -.rst-content .sphinx-tabs .sphinx-menu { - border-bottom-color: rgba(0, 0, 0, 0.25) !important; - display: flex; - flex-flow: row wrap -} - -.rst-content .sphinx-tabs .sphinx-menu a.active.item { - border-color: rgba(0, 0, 0, 0.25) !important -} - -.rst-content .sphinx-tab { - border-color: rgba(0, 0, 0, 0.25) !important; - box-sizing: border-box -} - -.rst-content .sphinx-tab.tab.active { - margin-bottom: 0 -} - -.rst-content .code-tab.tab { - padding: .4em !important -} - -.rst-content .code-tab.tab div[class^='highlight'] { - border: none -} - -.rst-content .sphinx-tabs .docutils.container { - margin: 0; - width: auto -} - -.rst-content .sphinx-tabs.docutils.container { - max-width: 100%; - padding: 0 -} - -.rst-content .sphinx-tabs .top.tabular.menu.docutils.container { - padding: 0 -} - -span[id*="MathJax-Span"] { - color: #212121 -} - -.t3-row { - background-color: #f2f2f2; - border-top: 2px solid #cbcbcb; - margin: 1rem 0; - padding: 0; - clear: both -} - -.t3-cell { - width: auto; - clear: both; - border-bottom: 4px solid white; - background-color: transparent; - padding: .5rem 1rem -} - -.t3-cell>*:last-child { - margin-bottom: 0 -} - -.t3-cell .term { - font-size: .875rem; - font-weight: normal; - color: #ff8700; - margin-bottom: 0 -} - -.t3-cell-property, -.t3-cell-datatype, -.t3-cell-key, -.t3-cell-default { - float: left; - clear: none; - font-weight: bold; - min-width: 30%; - border-right: 4px solid white -} - -ul[class*="horizbuttons-"] { - padding: 0 -} - -ul[class*="horizbuttons-"]>li { - line-height: 2em; - border-radius: .25rem; - display: inline; - padding: .25rem .5rem -} - -ul[class*="horizbuttons-"]>li>a { - color: inherit; - font-weight: bold -} - -ul[class*="horizbuttons-"][class*="-xxxl"] { - font-size: 1.5em -} - -ul[class*="horizbuttons-"][class*="-xxl"] { - font-size: 1.25em -} - -ul[class*="horizbuttons-"][class*="-warning-"]>li, -ul[class*="horizbuttons-"][class*="-attention-"]>li { - color: #212121; - background-color: #f0ad4e -} - -ul[class*="horizbuttons-"][class*="-tip-"]>li, -ul[class*="horizbuttons-"][class*="-important-"]>li { - color: #fff; - background-color: #5cb85c -} - -ul[class*="horizbuttons-"][class*="-note-"]>li { - color: #212121; - background-color: #5bc0de -} - -ul[class*="horizbuttons-"][class*="-typo3-"]>li, -ul[class*="horizbuttons-"][class*="-primary-"]>li { - color: #fff; - background-color: #ff8700 -} - -ul[class*="horizbuttons-"][class*="-striking-"]>li { - color: #fff; - background-color: #6c6c6c -} - -.autocomplete { - background-color: #fff; - background-clip: padding-box; - border: 1px solid #cecece; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2) -} - -.autocomplete>div { - padding: .375rem .75rem -} - -.autocomplete>div:not(.empty) { - cursor: pointer -} - -.autocomplete .selected { - color: #fff; - background-color: #ff8700 -} - -.highlighted { - color: #212121 !important; - background-color: #ffc107 !important -} - -.search { - padding: 0; - list-style: none; - list-style-image: none -} - -.search li { - margin-top: 1.5rem; - margin-bottom: 1.5rem; - padding-bottom: 1.5rem; - border-bottom: solid 1px rgba(0, 0, 0, 0.15) -} - -.search li:last-child { - padding-bottom: 0; - border-bottom: none -} - -.search a { - font-size: 1.25em; - display: block; - margin-bottom: .5em; - font-weight: 600; - line-height: 1.2 -} - -.panel { - background: #fff; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2); - border-radius: .25rem; - padding: 1.25rem 1.25rem; - border: 1px solid rgba(0, 0, 0, 0.125); - overflow: hidden -} - -.panel>*:last-child { - margin-bottom: 0 -} - -.panel>h1, -.panel>h2, -.panel>h3, -.panel>h4, -.panel>h5, -.panel>h6 { - font-size: 1.15rem; - padding: 1.25rem 1.25rem; - margin: -1.25rem -1.25rem; - margin-bottom: 1.25rem; - background-color: rgba(0, 0, 0, 0.03) -} - -.no-focus { - outline: none !important -} - -.cc { - clear: both -} - -.rubric { - font-weight: 700 -} - -/*# sourceMappingURL=theme.css.map */ \ No newline at end of file diff --git a/doc/rst/_static/css/book-ecal-addon.css b/doc/rst/_static/css/book-ecal-addon.css deleted file mode 100644 index af820da50a..0000000000 --- a/doc/rst/_static/css/book-ecal-addon.css +++ /dev/null @@ -1,13 +0,0 @@ -:root { - --pst-color-link: 255, 165, 0; -} - -@media (min-width:1200px) { - .container, - .container-lg, - .container-md, - .container-sm, - .container-xl { - max-width: 1500px - } -} \ No newline at end of file diff --git a/doc/rst/_static/css/pydata-ecal-addon.css b/doc/rst/_static/css/pydata-ecal-addon.css deleted file mode 100644 index 8a6b0ace41..0000000000 --- a/doc/rst/_static/css/pydata-ecal-addon.css +++ /dev/null @@ -1,8 +0,0 @@ -:root{ - --pst-color-link-hover: var(--pst-color-link); -} - -.admonition, -div.admonition { - box-shadow: 2px 2px .4rem rgba(0, 0, 0, .3), 0 0 .0625rem rgba(0, 0, 0, .2); -} \ No newline at end of file diff --git a/doc/rst/_static/css/pydata-ecal.css b/doc/rst/_static/css/pydata-ecal.css deleted file mode 100644 index 3a9b37e90b..0000000000 --- a/doc/rst/_static/css/pydata-ecal.css +++ /dev/null @@ -1,11883 +0,0 @@ -/*! - * Bootstrap v4.6.1 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -:root { - --blue: #ffa500; - --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: #ffa500; - --secondary: #6c757d; - --success: #28a745; - --info: #17a2b8; - --warning: #ffc107; - --danger: #dc3545; - --light: #f8f9fa; - --dark: #343a40; - --breakpoint-xs: 0; - --breakpoint-sm: 540px; - --breakpoint-md: 720px; - --breakpoint-lg: 960px; - --breakpoint-xl: 1200px; - --font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation 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: rgba(0, 0, 0, 0) -} - -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, Liberation Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; - font-size: 1rem; - line-height: 1.5; - color: #212529; - text-align: left -} - -[tabindex="-1"]:focus:not(:focus-visible) { - 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 { - font-style: normal; - line-height: inherit -} - -address, -dl, -ol, -ul { - margin-bottom: 1rem -} - -dl, -ol, -ul { - margin-top: 0 -} - -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: #ffa500; - background-color: transparent -} - -a:hover { - color: #B37400 -} - -a:not([href]):not([class]), -a:not([href]):not([class]):hover { - color: inherit; - text-decoration: none -} - -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; - -ms-overflow-style: scrollbar -} - -figure { - margin: 0 0 1rem -} - -img { - border-style: none -} - -img, -svg { - vertical-align: middle -} - -svg { - overflow: hidden -} - -table { - border-collapse: collapse -} - -caption { - padding-top: .75rem; - padding-bottom: .75rem; - color: #6c757d; - text-align: left; - caption-side: bottom -} - -th { - text-align: inherit; - text-align: -webkit-match-parent -} - -label { - display: inline-block; - margin-bottom: .5rem -} - -button { - border-radius: 0 -} - -button:focus:not(:focus-visible) { - outline: 0 -} - -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 -} - -[role=button] { - cursor: pointer -} - -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 -} - -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 -} - -.display-1, -.display-2 { - font-weight: 300; - line-height: 1.2 -} - -.display-2 { - font-size: 5.5rem -} - -.display-3 { - font-size: 4.5rem -} - -.display-3, -.display-4 { - font-weight: 300; - line-height: 1.2 -} - -.display-4 { - font-size: 3.5rem -} - -hr { - margin-top: 1rem; - margin-bottom: 1rem; - 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-inline, -.list-unstyled { - 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, -.img-thumbnail { - max-width: 100%; - height: auto -} - -.img-thumbnail { - padding: .25rem; - background-color: #fff; - border: 1px solid #dee2e6; - border-radius: .25rem -} - -.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-wrap: 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, -.container-fluid, -.container-lg, -.container-md, -.container-sm, -.container-xl { - width: 100%; - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto -} - -@media (min-width:540px) { - - .container, - .container-sm { - max-width: 540px - } -} - -@media (min-width:720px) { - - .container, - .container-md, - .container-sm { - max-width: 720px - } -} - -@media (min-width:960px) { - - .container, - .container-lg, - .container-md, - .container-sm { - max-width: 960px - } -} - -@media (min-width:1200px) { - - .container, - .container-lg, - .container-md, - .container-sm, - .container-xl { - max-width: 1400px - } -} - -.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-2, -.col-3, -.col-4, -.col-5, -.col-6, -.col-7, -.col-8, -.col-9, -.col-10, -.col-11, -.col-12, -.col-auto, -.col-lg, -.col-lg-1, -.col-lg-2, -.col-lg-3, -.col-lg-4, -.col-lg-5, -.col-lg-6, -.col-lg-7, -.col-lg-8, -.col-lg-9, -.col-lg-10, -.col-lg-11, -.col-lg-12, -.col-lg-auto, -.col-md, -.col-md-1, -.col-md-2, -.col-md-3, -.col-md-4, -.col-md-5, -.col-md-6, -.col-md-7, -.col-md-8, -.col-md-9, -.col-md-10, -.col-md-11, -.col-md-12, -.col-md-auto, -.col-sm, -.col-sm-1, -.col-sm-2, -.col-sm-3, -.col-sm-4, -.col-sm-5, -.col-sm-6, -.col-sm-7, -.col-sm-8, -.col-sm-9, -.col-sm-10, -.col-sm-11, -.col-sm-12, -.col-sm-auto, -.col-xl, -.col-xl-1, -.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-10, -.col-xl-11, -.col-xl-12, -.col-xl-auto { - position: relative; - width: 100%; - padding-right: 15px; - padding-left: 15px -} - -.col { - flex-basis: 0; - flex-grow: 1; - max-width: 100% -} - -.row-cols-1>* { - flex: 0 0 100%; - max-width: 100% -} - -.row-cols-2>* { - flex: 0 0 50%; - max-width: 50% -} - -.row-cols-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% -} - -.row-cols-4>* { - flex: 0 0 25%; - max-width: 25% -} - -.row-cols-5>* { - flex: 0 0 20%; - max-width: 20% -} - -.row-cols-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% -} - -.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:540px) { - .col-sm { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-sm-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-sm-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-sm-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-sm-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-sm-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-sm-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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:720px) { - .col-md { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-md-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-md-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-md-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-md-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-md-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-md-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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:960px) { - .col-lg { - flex-basis: 0; - flex-grow: 1; - max-width: 100% - } - - .row-cols-lg-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-lg-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-lg-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-lg-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-lg-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-lg-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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% - } - - .row-cols-xl-1>* { - flex: 0 0 100%; - max-width: 100% - } - - .row-cols-xl-2>* { - flex: 0 0 50%; - max-width: 50% - } - - .row-cols-xl-3>* { - flex: 0 0 33.33333%; - max-width: 33.33333% - } - - .row-cols-xl-4>* { - flex: 0 0 25%; - max-width: 25% - } - - .row-cols-xl-5>* { - flex: 0 0 20%; - max-width: 20% - } - - .row-cols-xl-6>* { - flex: 0 0 16.66667%; - max-width: 16.66667% - } - - .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, -.table-bordered td, -.table-bordered th { - border: 1px solid #dee2e6 -} - -.table-bordered thead td, -.table-bordered thead th { - border-bottom-width: 2px -} - -.table-borderless tbody+tbody, -.table-borderless td, -.table-borderless th, -.table-borderless thead th { - border: 0 -} - -.table-striped tbody tr:nth-of-type(odd) { - background-color: rgba(0, 0, 0, .05) -} - -.table-hover tbody tr:hover { - color: #212529; - background-color: rgba(0, 0, 0, .075) -} - -.table-primary, -.table-primary>td, -.table-primary>th { - background-color: #b8daff -} - -.table-primary tbody+tbody, -.table-primary td, -.table-primary th, -.table-primary thead th { - border-color: #FFD07A -} - -.table-hover .table-primary:hover, -.table-hover .table-primary:hover>td, -.table-hover .table-primary:hover>th { - background-color: #FFDD9F -} - -.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, -.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, -.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, -.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, -.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, -.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, -.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, -.table-hover .table-dark:hover>td, -.table-hover .table-dark:hover>th { - background-color: #b9bbbe -} - -.table-active, -.table-active>td, -.table-active>th, -.table-hover .table-active:hover, -.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: hsla(0, 0%, 100%, .05) -} - -.table-dark.table-hover tbody tr:hover { - color: #fff; - background-color: hsla(0, 0%, 100%, .075) -} - -@media (max-width:539.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:719.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:959.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: #FFD280; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .25) -} - -.form-control::placeholder { - color: #6c757d; - opacity: 1 -} - -.form-control:disabled, -.form-control[readonly] { - background-color: #e9ecef; - opacity: 1 -} - -input[type=date].form-control, -input[type=datetime-local].form-control, -input[type=month].form-control, -input[type=time].form-control { - appearance: none -} - -select.form-control:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #495057 -} - -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: .375rem 0; - margin-bottom: 0; - font-size: 1rem; - 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], -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, -.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%; - left: 0; - 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-row>.col>.valid-tooltip, -.form-row>[class*=col-]>.valid-tooltip { - left: 5px -} - -.is-valid~.valid-feedback, -.is-valid~.valid-tooltip, -.was-validated :valid~.valid-feedback, -.was-validated :valid~.valid-tooltip { - display: block -} - -.form-control.is-valid, -.was-validated .form-control:valid { - border-color: #28a745; - padding-right: calc(1.5em + .75rem) !important; - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='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: right calc(.375em + .1875rem) center; - 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) -} - -.was-validated select.form-control:valid, -select.form-control.is-valid { - padding-right: 3rem !important; - background-position: right 1.5rem center -} - -.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(.75em + 2.3125rem) !important; - background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat, #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='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") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat -} - -.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) -} - -.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: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, -.custom-file-input.is-valid~.custom-file-label, -.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label:before, -.was-validated .custom-file-input:valid~.custom-file-label { - border-color: #28a745 -} - -.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%; - left: 0; - 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-row>.col>.invalid-tooltip, -.form-row>[class*=col-]>.invalid-tooltip { - left: 5px -} - -.is-invalid~.invalid-feedback, -.is-invalid~.invalid-tooltip, -.was-validated :invalid~.invalid-feedback, -.was-validated :invalid~.invalid-tooltip { - display: block -} - -.form-control.is-invalid, -.was-validated .form-control:invalid { - border-color: #dc3545; - padding-right: calc(1.5em + .75rem) !important; - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: right calc(.375em + .1875rem) center; - 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) -} - -.was-validated select.form-control:invalid, -select.form-control.is-invalid { - padding-right: 3rem !important; - background-position: right 1.5rem center -} - -.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(.75em + 2.3125rem) !important; - background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat, #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23dc3545'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3E%3C/svg%3E") center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem) no-repeat -} - -.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) -} - -.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: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, -.custom-file-input.is-invalid~.custom-file-label, -.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label:before, -.was-validated .custom-file-input:invalid~.custom-file-label { - border-color: #dc3545 -} - -.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:540px) { - .form-inline label { - justify-content: center - } - - .form-inline .form-group, - .form-inline label { - display: flex; - align-items: center; - margin-bottom: 0 - } - - .form-inline .form-group { - flex: 0 0 auto; - flex-flow: row wrap - } - - .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(255, 162, 0, .25) -} - -.btn.disabled, -.btn:disabled { - opacity: .65 -} - -.btn:not(:disabled):not(.disabled) { - cursor: pointer -} - -a.btn.disabled, -fieldset:disabled a.btn { - pointer-events: none -} - -.btn-primary { - color: #fff; - background-color: #ffa500; - border-color: #ffa500 -} - -.btn-primary.focus, -.btn-primary:focus, -.btn-primary:hover { - color: #fff; - background-color: #D98C00; - border-color: #CC8400 -} - -.btn-primary.focus, -.btn-primary:focus { - box-shadow: 0 0 0 .2rem rgba(255,178,38, .5) -} - -.btn-primary.disabled, -.btn-primary:disabled { - color: #fff; - background-color: #ffa500; - border-color: #ffa500 -} - -.btn-primary:not(:disabled):not(.disabled).active, -.btn-primary:not(:disabled):not(.disabled):active, -.show>.btn-primary.dropdown-toggle { - color: #fff; - background-color: #CC8400; - border-color: #BF7C00 -} - -.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(255,178,38, .5) -} - -.btn-secondary { - color: #fff; - background-color: #6c757d; - border-color: #6c757d -} - -.btn-secondary.focus, -.btn-secondary:focus, -.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.focus, -.btn-success:focus, -.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.focus, -.btn-info:focus, -.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.focus, -.btn-warning:focus, -.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.focus, -.btn-danger:focus, -.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.focus, -.btn-light:focus, -.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.focus, -.btn-dark:focus, -.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: #ffa500; - border-color: #ffa500 -} - -.btn-outline-primary:hover { - color: #fff; - background-color: #ffa500; - border-color: #ffa500 -} - -.btn-outline-primary.focus, -.btn-outline-primary:focus { - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .5) -} - -.btn-outline-primary.disabled, -.btn-outline-primary:disabled { - color: #ffa500; - 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: #ffa500; - border-color: #ffa500 -} - -.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(255, 162, 0, .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: #ffa500; - text-decoration: none -} - -.btn-link:hover { - color: #B37400 -} - -.btn-link.focus, -.btn-link:focus, -.btn-link:hover { - text-decoration: underline -} - -.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:540px) { - .dropdown-menu-sm-left { - right: auto; - left: 0 - } - - .dropdown-menu-sm-right { - right: 0; - left: auto - } -} - -@media (min-width:720px) { - .dropdown-menu-md-left { - right: auto; - left: 0 - } - - .dropdown-menu-md-right { - right: 0; - left: auto - } -} - -@media (min-width:960px) { - .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: ""; - 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: #e9ecef -} - -.dropdown-item.active, -.dropdown-item:active { - color: #fff; - text-decoration: none; - background-color: #ffa500 -} - -.dropdown-item.disabled, -.dropdown-item:disabled { - color: #adb5bd; - 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.active, -.btn-group-vertical>.btn:active, -.btn-group-vertical>.btn:focus, -.btn-group-vertical>.btn:hover, -.btn-group>.btn.active, -.btn-group>.btn:active, -.btn-group>.btn:focus, -.btn-group>.btn:hover { - 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-group>.btn input[type=checkbox], -.btn-group-toggle>.btn-group>.btn input[type=radio], -.btn-group-toggle>.btn input[type=checkbox], -.btn-group-toggle>.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%; - min-width: 0; - 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(: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.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label, -.input-group.has-validation>.custom-file:nth-last-child(n+3) .custom-file-label:after, -.input-group.has-validation>.custom-select:nth-last-child(n+3), -.input-group.has-validation>.form-control:nth-last-child(n+3), -.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label, -.input-group:not(.has-validation)>.custom-file:not(:last-child) .custom-file-label:after, -.input-group:not(.has-validation)>.custom-select:not(:last-child), -.input-group:not(.has-validation)>.form-control:not(:last-child) { - border-top-right-radius: 0; - border-bottom-right-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.has-validation>.input-group-append:nth-last-child(n+3)>.btn, -.input-group.has-validation>.input-group-append:nth-last-child(n+3)>.input-group-text, -.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.btn, -.input-group:not(.has-validation)>.input-group-append:not(:last-child)>.input-group-text, -.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-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; - z-index: 1; - display: block; - min-height: 1.5rem; - padding-left: 1.5rem; - color-adjust: exact -} - -.custom-control-inline { - display: inline-flex; - margin-right: 1rem -} - -.custom-control-input { - position: absolute; - left: 0; - z-index: -1; - width: 1rem; - height: 1.25rem; - opacity: 0 -} - -.custom-control-input:checked~.custom-control-label:before { - color: #fff; - border-color: #ffa500; - background-color: #ffa500 -} - -.custom-control-input:focus~.custom-control-label:before { - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .25) -} - -.custom-control-input:focus:not(:checked)~.custom-control-label:before { - border-color: #FFD280 -} - -.custom-control-input:not(:disabled):active~.custom-control-label:before { - color: #fff; - background-color: #FFE4B3; - border-color: #FFE4B3 -} - -.custom-control-input:disabled~.custom-control-label, -.custom-control-input[disabled]~.custom-control-label { - color: #6c757d -} - -.custom-control-input:disabled~.custom-control-label:before, -.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 { - pointer-events: none; - background-color: #fff; - border: 1px solid #adb5bd -} - -.custom-control-label:after, -.custom-control-label:before { - position: absolute; - top: .25rem; - left: -1.5rem; - display: block; - width: 1rem; - height: 1rem; - content: "" -} - -.custom-control-label:after { - background: 50%/50% 50% no-repeat -} - -.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;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3E%3C/svg%3E") -} - -.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:before { - border-color: #ffa500; - background-color: #ffa500 -} - -.custom-checkbox .custom-control-input:indeterminate~.custom-control-label:after { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='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(255, 162, 0, .5) -} - -.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label:before { - background-color: rgba(255, 162, 0, .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;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' 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(255, 162, 0, .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(255, 162, 0, .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: #fff url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") right .75rem center/8px 10px no-repeat; - border: 1px solid #ced4da; - border-radius: .25rem; - appearance: none -} - -.custom-select:focus { - border-color: #FFD280; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .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:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #495057 -} - -.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 { - display: inline-block; - margin-bottom: 0 -} - -.custom-file, -.custom-file-input { - position: relative; - width: 100%; - height: calc(1.5em + .75rem + 2px) -} - -.custom-file-input { - z-index: 2; - margin: 0; - overflow: hidden; - opacity: 0 -} - -.custom-file-input:focus~.custom-file-label { - border-color: #FFD280; - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .25) -} - -.custom-file-input:disabled~.custom-file-label, -.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 { - left: 0; - z-index: 1; - height: calc(1.5em + .75rem + 2px); - overflow: hidden; - font-weight: 400; - background-color: #fff; - border: 1px solid #ced4da; - border-radius: .25rem -} - -.custom-file-label, -.custom-file-label:after { - position: absolute; - top: 0; - right: 0; - padding: .375rem .75rem; - line-height: 1.5; - color: #495057 -} - -.custom-file-label:after { - bottom: 0; - z-index: 3; - display: block; - height: calc(1.5em + .75rem); - content: "Browse"; - background-color: #e9ecef; - border-left: inherit; - border-radius: 0 .25rem .25rem 0 -} - -.custom-range { - width: 100%; - height: 1.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(255, 162, 0, .25) -} - -.custom-range:focus::-moz-range-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(255, 162, 0, .25) -} - -.custom-range:focus::-ms-thumb { - box-shadow: 0 0 0 1px #fff, 0 0 0 .2rem rgba(255, 162, 0, .25) -} - -.custom-range::-moz-focus-outer { - border: 0 -} - -.custom-range::-webkit-slider-thumb { - width: 1rem; - height: 1rem; - margin-top: -.25rem; - background-color: #ffa500; - 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: #FFE4B3 -} - -.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: #ffa500; - 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: #FFE4B3 -} - -.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: #ffa500; - 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: #FFE4B3 -} - -.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, -.custom-range::-ms-fill-upper { - background-color: #dee2e6; - border-radius: 1rem -} - -.custom-range::-ms-fill-upper { - margin-right: 15px -} - -.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-link { - margin-bottom: -1px; - 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: #ffa500 -} - -.nav-fill .nav-item, -.nav-fill>.nav-link { - flex: 1 1 auto; - text-align: center -} - -.nav-justified .nav-item, -.nav-justified>.nav-link { - flex-basis: 0; - flex-grow: 1; - text-align: center -} - -.tab-content>.tab-pane { - display: none -} - -.tab-content>.active { - display: block -} - -.navbar { - position: relative; - padding: .5rem 1rem -} - -.navbar, -.navbar .container, -.navbar .container-fluid, -.navbar .container-lg, -.navbar .container-md, -.navbar .container-sm, -.navbar .container-xl { - 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: 50%/100% 100% no-repeat -} - -.navbar-nav-scroll { - max-height: 75vh; - overflow-y: auto -} - -@media (max-width:539.98px) { - - .navbar-expand-sm>.container, - .navbar-expand-sm>.container-fluid, - .navbar-expand-sm>.container-lg, - .navbar-expand-sm>.container-md, - .navbar-expand-sm>.container-sm, - .navbar-expand-sm>.container-xl { - padding-right: 0; - padding-left: 0 - } -} - -@media (min-width:540px) { - .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, - .navbar-expand-sm>.container-lg, - .navbar-expand-sm>.container-md, - .navbar-expand-sm>.container-sm, - .navbar-expand-sm>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-sm .navbar-nav-scroll { - overflow: visible - } - - .navbar-expand-sm .navbar-collapse { - display: flex !important; - flex-basis: auto - } - - .navbar-expand-sm .navbar-toggler { - display: none - } -} - -@media (max-width:719.98px) { - - .navbar-expand-md>.container, - .navbar-expand-md>.container-fluid, - .navbar-expand-md>.container-lg, - .navbar-expand-md>.container-md, - .navbar-expand-md>.container-sm, - .navbar-expand-md>.container-xl { - padding-right: 0; - padding-left: 0 - } -} - -@media (min-width:720px) { - .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, - .navbar-expand-md>.container-lg, - .navbar-expand-md>.container-md, - .navbar-expand-md>.container-sm, - .navbar-expand-md>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-md .navbar-nav-scroll { - overflow: visible - } - - .navbar-expand-md .navbar-collapse { - display: flex !important; - flex-basis: auto - } - - .navbar-expand-md .navbar-toggler { - display: none - } -} - -@media (max-width:959.98px) { - - .navbar-expand-lg>.container, - .navbar-expand-lg>.container-fluid, - .navbar-expand-lg>.container-lg, - .navbar-expand-lg>.container-md, - .navbar-expand-lg>.container-sm, - .navbar-expand-lg>.container-xl { - padding-right: 0; - padding-left: 0 - } -} - -@media (min-width:960px) { - .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, - .navbar-expand-lg>.container-lg, - .navbar-expand-lg>.container-md, - .navbar-expand-lg>.container-sm, - .navbar-expand-lg>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-lg .navbar-nav-scroll { - overflow: visible - } - - .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, - .navbar-expand-xl>.container-lg, - .navbar-expand-xl>.container-md, - .navbar-expand-xl>.container-sm, - .navbar-expand-xl>.container-xl { - 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, - .navbar-expand-xl>.container-lg, - .navbar-expand-xl>.container-md, - .navbar-expand-xl>.container-sm, - .navbar-expand-xl>.container-xl { - flex-wrap: nowrap - } - - .navbar-expand-xl .navbar-nav-scroll { - overflow: visible - } - - .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, -.navbar-expand>.container-lg, -.navbar-expand>.container-md, -.navbar-expand>.container-sm, -.navbar-expand>.container-xl { - 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, -.navbar-expand>.container-lg, -.navbar-expand>.container-md, -.navbar-expand>.container-sm, -.navbar-expand>.container-xl { - flex-wrap: nowrap -} - -.navbar-expand .navbar-nav-scroll { - overflow: visible -} - -.navbar-expand .navbar-collapse { - display: flex !important; - flex-basis: auto -} - -.navbar-expand .navbar-toggler { - display: none -} - -.navbar-light .navbar-brand, -.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;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30'%3E%3Cpath stroke='rgba(0,0,0,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") -} - -.navbar-light .navbar-text { - color: rgba(0, 0, 0, .5) -} - -.navbar-light .navbar-text a, -.navbar-light .navbar-text a:focus, -.navbar-light .navbar-text a:hover { - color: rgba(0, 0, 0, .9) -} - -.navbar-dark .navbar-brand, -.navbar-dark .navbar-brand:focus, -.navbar-dark .navbar-brand:hover { - color: #fff -} - -.navbar-dark .navbar-nav .nav-link { - color: hsla(0, 0%, 100%, .5) -} - -.navbar-dark .navbar-nav .nav-link:focus, -.navbar-dark .navbar-nav .nav-link:hover { - color: hsla(0, 0%, 100%, .75) -} - -.navbar-dark .navbar-nav .nav-link.disabled { - color: hsla(0, 0%, 100%, .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: hsla(0, 0%, 100%, .5); - border-color: hsla(0, 0%, 100%, .1) -} - -.navbar-dark .navbar-toggler-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30'%3E%3Cpath stroke='rgba(255,255,255,0.5)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") -} - -.navbar-dark .navbar-text { - color: hsla(0, 0%, 100%, .5) -} - -.navbar-dark .navbar-text a, -.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 { - border-top: inherit; - border-bottom: inherit -} - -.card>.list-group:first-child { - border-top-width: 0; - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.card>.list-group:last-child { - border-bottom-width: 0; - border-bottom-right-radius: calc(.25rem - 1px); - border-bottom-left-radius: calc(.25rem - 1px) -} - -.card>.card-header+.list-group, -.card>.list-group+.card-footer { - border-top: 0 -} - -.card-body { - flex: 1 1 auto; - min-height: 1px; - padding: 1.25rem -} - -.card-title { - margin-bottom: .75rem -} - -.card-subtitle { - margin-top: -.375rem -} - -.card-subtitle, -.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-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-bottom: -.75rem; - border-bottom: 0 -} - -.card-header-pills, -.card-header-tabs { - margin-right: -.625rem; - margin-left: -.625rem -} - -.card-img-overlay { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - padding: 1.25rem; - border-radius: calc(.25rem - 1px) -} - -.card-img, -.card-img-bottom, -.card-img-top { - flex-shrink: 0; - width: 100% -} - -.card-img, -.card-img-top { - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.card-img, -.card-img-bottom { - border-bottom-right-radius: calc(.25rem - 1px); - border-bottom-left-radius: calc(.25rem - 1px) -} - -.card-deck .card { - margin-bottom: 15px -} - -@media (min-width:540px) { - .card-deck { - display: flex; - flex-flow: row wrap; - margin-right: -15px; - margin-left: -15px - } - - .card-deck .card { - flex: 1 0 0%; - margin-right: 15px; - margin-bottom: 0; - margin-left: 15px - } -} - -.card-group>.card { - margin-bottom: 15px -} - -@media (min-width:540px) { - .card-group { - display: flex; - 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:540px) { - .card-columns { - column-count: 3; - column-gap: 1.25rem; - orphans: 1; - widows: 1 - } - - .card-columns .card { - display: inline-block; - width: 100% - } -} - -.accordion { - overflow-anchor: none -} - -.accordion>.card { - overflow: hidden -} - -.accordion>.card:not(:last-of-type) { - border-bottom: 0; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0 -} - -.accordion>.card:not(:first-of-type) { - border-top-left-radius: 0; - border-top-right-radius: 0 -} - -.accordion>.card>.card-header { - border-radius: 0; - 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 { - float: left; - padding-right: .5rem; - color: #6c757d; - content: "/" -} - -.breadcrumb-item+.breadcrumb-item:hover:before { - text-decoration: underline; - 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: #ffa500; - background-color: #fff; - border: 1px solid #dee2e6 -} - -.page-link:hover { - z-index: 2; - color: #B37400; - text-decoration: none; - background-color: #e9ecef; - border-color: #dee2e6 -} - -.page-link:focus { - z-index: 3; - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .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: 3; - color: #fff; - background-color: #ffa500; - border-color: #ffa500 -} - -.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: #ffa500 -} - -a.badge-primary:focus, -a.badge-primary:hover { - color: #fff; - background-color: #CC8400 -} - -a.badge-primary.focus, -a.badge-primary:focus { - outline: 0; - box-shadow: 0 0 0 .2rem rgba(255, 162, 0, .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:540px) { - .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; - z-index: 2; - padding: .75rem 1.25rem; - color: inherit -} - -.alert-primary { - color: #004085; - background-color: #cce5ff; - border-color: #b8daff -} - -.alert-primary hr { - border-top-color: #FFDD9F -} - -.alert-primary .alert-link { - color: #002752 -} - -.alert-secondary { - color: #383d41; - background-color: #e2e3e5; - border-color: #d6d8db -} - -.alert-secondary hr { - border-top-color: #c8cbcf -} - -.alert-secondary .alert-link { - color: #202326 -} - -.alert-success { - color: #155724; - background-color: #d4edda; - border-color: #c3e6cb -} - -.alert-success hr { - border-top-color: #b1dfbb -} - -.alert-success .alert-link { - color: #0b2e13 -} - -.alert-info { - color: #0c5460; - background-color: #d1ecf1; - border-color: #bee5eb -} - -.alert-info hr { - border-top-color: #abdde5 -} - -.alert-info .alert-link { - color: #062c33 -} - -.alert-warning { - color: #856404; - background-color: #fff3cd; - border-color: #ffeeba -} - -.alert-warning hr { - border-top-color: #ffe8a1 -} - -.alert-warning .alert-link { - color: #533f03 -} - -.alert-danger { - color: #721c24; - background-color: #f8d7da; - border-color: #f5c6cb -} - -.alert-danger hr { - border-top-color: #f1b0b7 -} - -.alert-danger .alert-link { - color: #491217 -} - -.alert-light { - color: #818182; - background-color: #fefefe; - border-color: #fdfdfe -} - -.alert-light hr { - border-top-color: #ececf6 -} - -.alert-light .alert-link { - color: #686868 -} - -.alert-dark { - color: #1b1e21; - background-color: #d6d8d9; - border-color: #c6c8ca -} - -.alert-dark hr { - border-top-color: #b9bbbe -} - -.alert-dark .alert-link { - color: #040505 -} - -@keyframes progress-bar-stripes { - 0% { - background-position: 1rem 0 - } - - to { - background-position: 0 0 - } -} - -.progress { - height: 1rem; - line-height: 0; - font-size: .75rem; - background-color: #e9ecef; - border-radius: .25rem -} - -.progress, -.progress-bar { - display: flex; - overflow: hidden -} - -.progress-bar { - flex-direction: column; - justify-content: center; - color: #fff; - text-align: center; - white-space: nowrap; - background-color: #ffa500; - transition: width .6s ease -} - -@media (prefers-reduced-motion:reduce) { - .progress-bar { - transition: none - } -} - -.progress-bar-striped { - background-image: linear-gradient(45deg, hsla(0, 0%, 100%, .15) 25%, transparent 0, transparent 50%, hsla(0, 0%, 100%, .15) 0, hsla(0, 0%, 100%, .15) 75%, transparent 0, 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; - border-radius: .25rem -} - -.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; - background-color: #fff; - border: 1px solid rgba(0, 0, 0, .125) -} - -.list-group-item:first-child { - border-top-left-radius: inherit; - border-top-right-radius: inherit -} - -.list-group-item:last-child { - border-bottom-right-radius: inherit; - border-bottom-left-radius: inherit -} - -.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: #ffa500; - border-color: #ffa500 -} - -.list-group-item+.list-group-item { - border-top-width: 0 -} - -.list-group-item+.list-group-item.active { - margin-top: -1px; - border-top-width: 1px -} - -.list-group-horizontal { - flex-direction: row -} - -.list-group-horizontal>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 -} - -.list-group-horizontal>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 -} - -.list-group-horizontal>.list-group-item.active { - margin-top: 0 -} - -.list-group-horizontal>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 -} - -.list-group-horizontal>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px -} - -@media (min-width:540px) { - .list-group-horizontal-sm { - flex-direction: row - } - - .list-group-horizontal-sm>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-sm>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-sm>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-sm>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-sm>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width:720px) { - .list-group-horizontal-md { - flex-direction: row - } - - .list-group-horizontal-md>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-md>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-md>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-md>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-md>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width:960px) { - .list-group-horizontal-lg { - flex-direction: row - } - - .list-group-horizontal-lg>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-lg>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-lg>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-lg>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-lg>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -@media (min-width:1200px) { - .list-group-horizontal-xl { - flex-direction: row - } - - .list-group-horizontal-xl>.list-group-item:first-child { - border-bottom-left-radius: .25rem; - border-top-right-radius: 0 - } - - .list-group-horizontal-xl>.list-group-item:last-child { - border-top-right-radius: .25rem; - border-bottom-left-radius: 0 - } - - .list-group-horizontal-xl>.list-group-item.active { - margin-top: 0 - } - - .list-group-horizontal-xl>.list-group-item+.list-group-item { - border-top-width: 1px; - border-left-width: 0 - } - - .list-group-horizontal-xl>.list-group-item+.list-group-item.active { - margin-left: -1px; - border-left-width: 1px - } -} - -.list-group-flush { - border-radius: 0 -} - -.list-group-flush>.list-group-item { - border-width: 0 0 1px -} - -.list-group-flush>.list-group-item:last-child { - border-bottom-width: 0 -} - -.list-group-item-primary { - color: #004085; - background-color: #b8daff -} - -.list-group-item-primary.list-group-item-action:focus, -.list-group-item-primary.list-group-item-action:hover { - color: #004085; - background-color: #FFDD9F -} - -.list-group-item-primary.list-group-item-action.active { - color: #fff; - background-color: #004085; - border-color: #004085 -} - -.list-group-item-secondary { - color: #383d41; - background-color: #d6d8db -} - -.list-group-item-secondary.list-group-item-action:focus, -.list-group-item-secondary.list-group-item-action:hover { - color: #383d41; - background-color: #c8cbcf -} - -.list-group-item-secondary.list-group-item-action.active { - color: #fff; - background-color: #383d41; - border-color: #383d41 -} - -.list-group-item-success { - color: #155724; - background-color: #c3e6cb -} - -.list-group-item-success.list-group-item-action:focus, -.list-group-item-success.list-group-item-action:hover { - color: #155724; - background-color: #b1dfbb -} - -.list-group-item-success.list-group-item-action.active { - color: #fff; - background-color: #155724; - border-color: #155724 -} - -.list-group-item-info { - color: #0c5460; - background-color: #bee5eb -} - -.list-group-item-info.list-group-item-action:focus, -.list-group-item-info.list-group-item-action:hover { - color: #0c5460; - background-color: #abdde5 -} - -.list-group-item-info.list-group-item-action.active { - color: #fff; - background-color: #0c5460; - border-color: #0c5460 -} - -.list-group-item-warning { - color: #856404; - background-color: #ffeeba -} - -.list-group-item-warning.list-group-item-action:focus, -.list-group-item-warning.list-group-item-action:hover { - color: #856404; - background-color: #ffe8a1 -} - -.list-group-item-warning.list-group-item-action.active { - color: #fff; - background-color: #856404; - border-color: #856404 -} - -.list-group-item-danger { - color: #721c24; - background-color: #f5c6cb -} - -.list-group-item-danger.list-group-item-action:focus, -.list-group-item-danger.list-group-item-action:hover { - color: #721c24; - background-color: #f1b0b7 -} - -.list-group-item-danger.list-group-item-action.active { - color: #fff; - background-color: #721c24; - border-color: #721c24 -} - -.list-group-item-light { - color: #818182; - background-color: #fdfdfe -} - -.list-group-item-light.list-group-item-action:focus, -.list-group-item-light.list-group-item-action:hover { - color: #818182; - background-color: #ececf6 -} - -.list-group-item-light.list-group-item-action.active { - color: #fff; - background-color: #818182; - border-color: #818182 -} - -.list-group-item-dark { - color: #1b1e21; - background-color: #c6c8ca -} - -.list-group-item-dark.list-group-item-action:focus, -.list-group-item-dark.list-group-item-action:hover { - color: #1b1e21; - background-color: #b9bbbe -} - -.list-group-item-dark.list-group-item-action.active { - color: #fff; - background-color: #1b1e21; - border-color: #1b1e21 -} - -.close { - float: right; - font-size: 1.5rem; - font-weight: 700; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - opacity: .5 -} - -.close:hover { - color: #000; - text-decoration: none -} - -.close:not(:disabled):not(.disabled):focus, -.close:not(:disabled):not(.disabled):hover { - opacity: .75 -} - -button.close { - padding: 0; - background-color: transparent; - border: 0 -} - -a.close.disabled { - pointer-events: none -} - -.toast { - flex-basis: 350px; - max-width: 350px; - font-size: .875rem; - background-color: hsla(0, 0%, 100%, .85); - background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, .1); - box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .1); - 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: hsla(0, 0%, 100%, .85); - background-clip: padding-box; - border-bottom: 1px solid rgba(0, 0, 0, .05); - border-top-left-radius: calc(.25rem - 1px); - border-top-right-radius: calc(.25rem - 1px) -} - -.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: translateY(-50px) -} - -@media (prefers-reduced-motion:reduce) { - .modal.fade .modal-dialog { - transition: none - } -} - -.modal.show .modal-dialog { - transform: none -} - -.modal.modal-static .modal-dialog { - transform: scale(1.02) -} - -.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); - height: min-content; - 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; - border-bottom: 1px solid #dee2e6; - border-top-left-radius: calc(.3rem - 1px); - border-top-right-radius: calc(.3rem - 1px) -} - -.modal-header .close { - padding: 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; - flex-wrap: wrap; - align-items: center; - justify-content: flex-end; - padding: .75rem; - border-top: 1px solid #dee2e6; - border-bottom-right-radius: calc(.3rem - 1px); - border-bottom-left-radius: calc(.3rem - 1px) -} - -.modal-footer>* { - margin: .25rem -} - -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll -} - -@media (min-width:540px) { - .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); - height: min-content - } - - .modal-sm { - max-width: 300px - } -} - -@media (min-width:960px) { - - .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, Liberation 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 { - top: 0; - left: 0; - z-index: 1060; - max-width: 276px; - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, Liberation 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, -.popover .arrow { - position: absolute; - display: block -} - -.popover .arrow { - 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) -} - -.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); - 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) -} - -.bs-popover-auto[x-placement^=bottom]>.arrow:before, -.bs-popover-bottom>.arrow:before { - top: 0; - border-width: 0 .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; - 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); - 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: opacity 0s .6s -} - -@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%; - padding: 0; - color: #fff; - text-align: center; - background: none; - border: 0; - 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: 50%/100% 100% no-repeat -} - -.carousel-control-prev-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8'%3E%3Cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3E%3C/svg%3E") -} - -.carousel-control-next-icon { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8'%3E%3Cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-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(1turn) - } -} - -.spinner-border { - display: inline-block; - width: 2rem; - height: 2rem; - vertical-align: -.125em; - border: .25em solid; - border-right: .25em solid 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; - transform: none - } -} - -.spinner-grow { - display: inline-block; - width: 2rem; - height: 2rem; - vertical-align: -.125em; - background-color: currentColor; - border-radius: 50%; - opacity: 0; - animation: spinner-grow .75s linear infinite -} - -.spinner-grow-sm { - width: 1rem; - height: 1rem -} - -@media (prefers-reduced-motion:reduce) { - - .spinner-border, - .spinner-grow { - animation-duration: 1.5s - } -} - -.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: #ffa500 !important -} - -a.bg-primary:focus, -a.bg-primary:hover, -button.bg-primary:focus, -button.bg-primary:hover { - background-color: #CC8400 !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: #ffa500 !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 -} - -.rounded-right, -.rounded-top { - border-top-right-radius: .25rem !important -} - -.rounded-bottom, -.rounded-right { - border-bottom-right-radius: .25rem !important -} - -.rounded-bottom, -.rounded-left { - border-bottom-left-radius: .25rem !important -} - -.rounded-left { - border-top-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:540px) { - .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:720px) { - .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:960px) { - .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:540px) { - .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:720px) { - .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:960px) { - .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:540px) { - .float-sm-left { - float: left !important - } - - .float-sm-right { - float: right !important - } - - .float-sm-none { - float: none !important - } -} - -@media (min-width:720px) { - .float-md-left { - float: left !important - } - - .float-md-right { - float: right !important - } - - .float-md-none { - float: none !important - } -} - -@media (min-width:960px) { - .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 - } -} - -.user-select-all { - user-select: all !important -} - -.user-select-auto { - user-select: auto !important -} - -.user-select-none { - user-select: 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 { - top: 0 -} - -.fixed-bottom, -.fixed-top { - position: fixed; - right: 0; - left: 0; - z-index: 1030 -} - -.fixed-bottom { - bottom: 0 -} - -@supports (position:sticky) { - .sticky-top { - position: sticky; - top: 0; - z-index: 1020 - } -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - 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 -} - -.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:540px) { - .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:720px) { - .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:960px) { - .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 - } -} - -.stretched-link:after { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1; - pointer-events: auto; - content: ""; - background-color: transparent -} - -.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:540px) { - .text-sm-left { - text-align: left !important - } - - .text-sm-right { - text-align: right !important - } - - .text-sm-center { - text-align: center !important - } -} - -@media (min-width:720px) { - .text-md-left { - text-align: left !important - } - - .text-md-right { - text-align: right !important - } - - .text-md-center { - text-align: center !important - } -} - -@media (min-width:960px) { - .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: #ffa500 !important -} - -a.text-primary:focus, -a.text-primary:hover { - color: #B37400 !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: hsla(0, 0%, 100%, .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; - word-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 - } - - blockquote, - img, - pre, - tr { - page-break-inside: avoid - } - - h2, - h3, - p { - orphans: 3; - widows: 3 - } - - h2, - h3 { - page-break-after: avoid - } - - @page { - size: a3 - } - - .container, - body { - min-width: 960px !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 - } -} - -html { - font-size: var(--pst-font-size-base); - scroll-padding-top: calc(var(--pst-header-height) + 12px) -} - -body { - padding-top: var(--pst-header-height); - background-color: #fff; - font-family: var(--pst-font-family-base); - font-weight: 400; - line-height: 1.65; - color: rgba(var(--pst-color-text-base), 1) -} - -p { - margin-bottom: 1.15rem; - font-size: 1em; - color: rgba(var(--pst-color-paragraph), 1) -} - -p.rubric { - border-bottom: 1px solid #c9c9c9 -} - -a { - color: rgba(var(--pst-color-link), 1); - text-decoration: none -} - -a:hover { - color: rgba(var(--pst-color-link-hover), 1); - text-decoration: underline -} - -a.headerlink { - color: rgba(var(--pst-color-headerlink), 1); - opacity: .4; - font-size: .8em; - padding: 0 4px; - margin-left: .2em; - text-decoration: none; - transition: all .3s ease-out; - user-select: none -} - -a.headerlink:hover { - opacity: 1 -} - -.heading-style, -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 2.75rem 0 1.05rem; - font-family: var(--pst-font-family-heading); - font-weight: 400; - line-height: 1.15 -} - -h1 { - margin-top: 0; - font-size: var(--pst-font-size-h1); - color: rgba(var(--pst-color-h1), 1) -} - -h2 { - font-size: var(--pst-font-size-h2); - color: rgba(var(--pst-color-h2), 1) -} - -h3 { - font-size: var(--pst-font-size-h3); - color: rgba(var(--pst-color-h3), 1) -} - -h4 { - font-size: var(--pst-font-size-h4); - color: rgba(var(--pst-color-h4), 1) -} - -h5 { - font-size: var(--pst-font-size-h5); - color: rgba(var(--pst-color-h5), 1) -} - -h6 { - font-size: var(--pst-font-size-h6); - color: rgba(var(--pst-color-h6), 1) -} - -.text_small, -small { - font-size: var(--pst-font-size-milli) -} - -hr { - border: 0; - border-top: 1px solid #e5e5e5 -} - -code, -kbd, -pre, -samp { - font-family: var(--pst-font-family-monospace) -} - -code { - color: rgba(var(--pst-color-inline-code), 1) -} - -pre { - margin: 1.5em 0; - padding: 10px; - background-color: rgba(var(--pst-color-preformatted-background), 1); - color: rgba(var(--pst-color-preformatted-text), 1); - line-height: 1.2em; - border: 1px solid #c9c9c9; - border-radius: .2rem; - box-shadow: 1px 1px 1px #d8d8d8 -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) minmax(0, 1fr) -} - -.navbar { - position: fixed; - min-height: var(--pst-header-height); - width: 100%; - padding: 0 -} - -.navbar .container-xl { - height: 100% -} - -@media (max-width:1199.98px) { - .navbar #navbar-start { - margin-left: 1em - } - - .navbar button.navbar-toggler { - margin-right: 1em - } -} - -@media (min-width:960px) { - .navbar #navbar-end>.navbar-end-item { - display: inline-block - } -} - -.navbar-brand { - position: relative; - height: var(--pst-header-height); - width: auto; - padding: .5rem 0; - display: flex; - align-items: center -} - -.navbar-brand p { - margin-bottom: 0 -} - -.navbar-brand img { - max-width: 100%; - height: 100%; - width: auto -} - -.navbar-light { - background: #fff !important; - box-shadow: 0 .125rem .25rem 0 rgba(0, 0, 0, .11) -} - -.navbar-light .navbar-nav li a.nav-link { - padding: 0 .5rem; - color: rgba(var(--pst-color-navbar-link), 1) -} - -.navbar-light .navbar-nav li a.nav-link:hover { - color: rgba(var(--pst-color-navbar-link-hover), 1) -} - -.navbar-light .navbar-nav>.active>.nav-link { - font-weight: 600; - color: rgba(var(--pst-color-navbar-link-active), 1) -} - -.navbar-header a { - padding: 0 15px -} - -.admonition, -div.admonition { - margin: 1.5625em auto; - padding: 0 .6rem .8rem; - overflow: hidden; - page-break-inside: avoid; - border-left: .2rem solid; - border-left-color: rgba(var(--pst-color-admonition-default), 1); - border-bottom-color: rgba(var(--pst-color-admonition-default), 1); - border-right-color: rgba(var(--pst-color-admonition-default), 1); - border-top-color: rgba(var(--pst-color-admonition-default), 1); - border-radius: .2rem; - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1); - transition: color .25s, background-color .25s, border-color .25s -} - -.admonition :last-child, -div.admonition :last-child { - margin-bottom: 0 -} - -.admonition p.admonition-title~*, -div.admonition p.admonition-title~* { - margin-left: 1.4rem; - margin-right: 1.4rem -} - -.admonition>ol, -.admonition>ul, -div.admonition>ol, -div.admonition>ul { - margin-left: 1em -} - -.admonition>.admonition-title, -div.admonition>.admonition-title { - position: relative; - margin: 0 -.6rem; - padding: .4rem .6rem .4rem 2rem; - font-weight: 700; - background-color: rgba(var(--pst-color-admonition-default), .1) -} - -.admonition>.admonition-title:before, -div.admonition>.admonition-title:before { - position: absolute; - left: .6rem; - width: 1rem; - height: 1rem; - color: rgba(var(--pst-color-admonition-default), 1); - font-family: Font Awesome\ 5 Free; - font-weight: 900; - content: var(--pst-icon-admonition-default) -} - -.admonition>.admonition-title+*, -div.admonition>.admonition-title+* { - margin-top: .4em -} - -.admonition.attention, -div.admonition.attention { - border-color: rgba(var(--pst-color-admonition-attention), 1) -} - -.admonition.attention>.admonition-title, -div.admonition.attention>.admonition-title { - background-color: rgba(var(--pst-color-admonition-attention), .1) -} - -.admonition.attention>.admonition-title:before, -div.admonition.attention>.admonition-title:before { - color: rgba(var(--pst-color-admonition-attention), 1); - content: var(--pst-icon-admonition-attention) -} - -.admonition.caution, -div.admonition.caution { - border-color: rgba(var(--pst-color-admonition-caution), 1) -} - -.admonition.caution>.admonition-title, -div.admonition.caution>.admonition-title { - background-color: rgba(var(--pst-color-admonition-caution), .1) -} - -.admonition.caution>.admonition-title:before, -div.admonition.caution>.admonition-title:before { - color: rgba(var(--pst-color-admonition-caution), 1); - content: var(--pst-icon-admonition-caution) -} - -.admonition.warning, -div.admonition.warning { - border-color: rgba(var(--pst-color-admonition-warning), 1) -} - -.admonition.warning>.admonition-title, -div.admonition.warning>.admonition-title { - background-color: rgba(var(--pst-color-admonition-warning), .1) -} - -.admonition.warning>.admonition-title:before, -div.admonition.warning>.admonition-title:before { - color: rgba(var(--pst-color-admonition-warning), 1); - content: var(--pst-icon-admonition-warning) -} - -.admonition.danger, -div.admonition.danger { - border-color: rgba(var(--pst-color-admonition-danger), 1) -} - -.admonition.danger>.admonition-title, -div.admonition.danger>.admonition-title { - background-color: rgba(var(--pst-color-admonition-danger), .1) -} - -.admonition.danger>.admonition-title:before, -div.admonition.danger>.admonition-title:before { - color: rgba(var(--pst-color-admonition-danger), 1); - content: var(--pst-icon-admonition-danger) -} - -.admonition.error, -div.admonition.error { - border-color: rgba(var(--pst-color-admonition-error), 1) -} - -.admonition.error>.admonition-title, -div.admonition.error>.admonition-title { - background-color: rgba(var(--pst-color-admonition-error), .1) -} - -.admonition.error>.admonition-title:before, -div.admonition.error>.admonition-title:before { - color: rgba(var(--pst-color-admonition-error), 1); - content: var(--pst-icon-admonition-error) -} - -.admonition.hint, -div.admonition.hint { - border-color: rgba(var(--pst-color-admonition-hint), 1) -} - -.admonition.hint>.admonition-title, -div.admonition.hint>.admonition-title { - background-color: rgba(var(--pst-color-admonition-hint), .1) -} - -.admonition.hint>.admonition-title:before, -div.admonition.hint>.admonition-title:before { - color: rgba(var(--pst-color-admonition-hint), 1); - content: var(--pst-icon-admonition-hint) -} - -.admonition.tip, -div.admonition.tip { - border-color: rgba(var(--pst-color-admonition-tip), 1) -} - -.admonition.tip>.admonition-title, -div.admonition.tip>.admonition-title { - background-color: rgba(var(--pst-color-admonition-tip), .1) -} - -.admonition.tip>.admonition-title:before, -div.admonition.tip>.admonition-title:before { - color: rgba(var(--pst-color-admonition-tip), 1); - content: var(--pst-icon-admonition-tip) -} - -.admonition.important, -div.admonition.important { - border-color: rgba(var(--pst-color-admonition-important), 1) -} - -.admonition.important>.admonition-title, -div.admonition.important>.admonition-title { - background-color: rgba(var(--pst-color-admonition-important), .1) -} - -.admonition.important>.admonition-title:before, -div.admonition.important>.admonition-title:before { - color: rgba(var(--pst-color-admonition-important), 1); - content: var(--pst-icon-admonition-important) -} - -.admonition.note, -div.admonition.note { - border-color: rgba(var(--pst-color-admonition-note), 1) -} - -.admonition.note>.admonition-title, -div.admonition.note>.admonition-title { - background-color: rgba(var(--pst-color-admonition-note), .1) -} - -.admonition.note>.admonition-title:before, -div.admonition.note>.admonition-title:before { - color: rgba(var(--pst-color-admonition-note), 1); - content: var(--pst-icon-admonition-note) -} - -table.field-list { - border-collapse: separate; - border-spacing: 10px; - margin-left: 1px -} - -table.field-list th.field-name { - padding: 1px 8px 1px 5px; - white-space: nowrap; - background-color: #eee -} - -table.field-list td.field-body p { - font-style: italic -} - -table.field-list td.field-body p>strong { - font-style: normal -} - -table.field-list td.field-body blockquote { - border-left: none; - margin: 0 0 .3em; - padding-left: 30px -} - -.table.autosummary td:first-child { - white-space: nowrap -} - -.sig { - font-family: var(--pst-font-family-monospace) -} - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset -} - -.sig.c .k, -.sig.c .kt, -.sig.c .m, -.sig.c .s, -.sig.c .sc, -.sig.cpp .k, -.sig.cpp .kt, -.sig.cpp .m, -.sig.cpp .s, -.sig.cpp .sc { - color: rgba(var(--pst-color-text-base), 1) -} - -.sig-name { - color: rgba(var(--pst-color-inline-code), 1) -} - -td.text-align\:left, -th.text-align\:left { - text-align: left -} - -td.text-align\:right, -th.text-align\:right { - text-align: right -} - -td.text-align\:center, -th.text-align\:center { - text-align: center -} - -div.deprecated, -div.versionadded, -div.versionchanged { - vertical-align: middle; - margin: 1.5625em auto; - padding: 0 .6rem; - overflow: hidden; - page-break-inside: avoid; - border-left: .2rem solid; - border-left-color: rgba(var(--pst-color-versionmodified-default), 1); - border-bottom-color: rgba(var(--pst-color-versionmodified-default), 1); - border-right-color: rgba(var(--pst-color-versionmodified-default), 1); - border-top-color: rgba(var(--pst-color-versionmodified-default), 1); - border-radius: .2rem; - box-shadow: 0 .2rem .5rem rgba(0, 0, 0, .05), 0 0 .0625rem rgba(0, 0, 0, .1); - transition: color .25s, background-color .25s, border-color .25s; - background-color: rgba(var(--pst-color-admonition-default), .1) -} - -div.deprecated>p, -div.versionadded>p, -div.versionchanged>p { - margin-bottom: .6rem; - margin-top: .6rem -} - -div.versionadded { - border-color: rgba(var(--pst-color-versionmodified-added), 1); - background-color: rgba(var(--pst-color-versionmodified-added), .1) -} - -div.versionchanged { - border-color: rgba(var(--pst-color-versionmodified-changed), 1); - background-color: rgba(var(--pst-color-versionmodified-changed), .1) -} - -div.deprecated { - border-color: rgba(var(--pst-color-versionmodified-deprecated), 1); - background-color: rgba(var(--pst-color-versionmodified-deprecated), .1) -} - -span.versionmodified { - font-weight: 700 -} - -span.versionmodified:before { - font-style: normal; - margin-right: .6rem; - color: rgba(var(--pst-color-versionmodified-default), 1); - font-family: Font Awesome\ 5 Free; - font-weight: 900; - content: var(--pst-icon-versionmodified-default) -} - -span.versionmodified.added:before { - color: rgba(var(--pst-color-versionmodified-added), 1); - content: var(--pst-icon-versionmodified-added) -} - -span.versionmodified.changed:before { - color: rgba(var(--pst-color-versionmodified-changed), 1); - content: var(--pst-icon-versionmodified-changed) -} - -span.versionmodified.deprecated:before { - color: rgba(var(--pst-color-versionmodified-deprecated), 1); - content: var(--pst-icon-versionmodified-deprecated) -} - -blockquote { - padding: 0 1em; - color: #6a737d; - border-left: .25em solid #dfe2e5 -} - -dt.label>span.brackets:not(:only-child):before { - content: "[" -} - -dt.label>span.brackets:not(:only-child):after { - content: "]" -} - -a.footnote-reference { - vertical-align: super; - font-size: small -} - -.topic { - background-color: #eee -} - -.seealso dd { - margin-top: 0; - margin-bottom: 0 -} - -.viewcode-back { - font-family: var(--pst-font-family-base) -} - -.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9 -} - -span.guilabel { - border: 1px solid #7fbbe3; - background: #e7f2fa; - font-size: 80%; - font-weight: 700; - border-radius: 4px; - padding: 2.4px 6px; - margin: auto 2px -} - -footer { - width: 100%; - border-top: 1px solid #ccc; - padding: 10px -} - -footer .footer-item p { - margin-bottom: 0 -} - -.bd-search { - position: relative; - padding: 1rem 15px; - margin-right: -15px; - margin-left: -15px -} - -.bd-search .icon { - position: absolute; - color: #a4a6a7; - left: 25px -} - -.bd-search input { - border-radius: .2rem; - border: 1px solid #e5e5e5; - padding-left: 35px -} - -.bd-toc { - -ms-flex-order: 2; - order: 2; - height: calc(100vh - 2rem); - overflow-y: auto -} - -@supports (position:-webkit-sticky) or (position:sticky) { - .bd-toc { - position: -webkit-sticky; - position: sticky; - top: var(--pst-header-height); - height: calc(100vh - 5rem); - overflow-y: auto - } -} - -.bd-toc .onthispage { - color: #a4a6a7 -} - -.section-nav { - padding-left: 0; - border-left: 1px solid #eee; - border-bottom: none -} - -.section-nav ul { - padding-left: 1rem -} - -.toc-entry, -.toc-entry a { - display: block -} - -.toc-entry a { - padding: .125rem 1.5rem; - color: rgba(var(--pst-color-toc-link), 1) -} - -@media (min-width:1200px) { - .toc-entry a { - padding-right: 0 - } -} - -.toc-entry a:hover { - color: rgba(var(--pst-color-toc-link-hover), 1); - text-decoration: none -} - -.bd-links { - padding-top: 1rem; - padding-bottom: 1rem; - margin-right: -15px; - margin-left: -15px -} - -@media (min-width:720px) { - .bd-links { - display: block - } -} - -.bd-sidenav { - display: none -} - -.bd-content { - padding-top: 20px -} - -.bd-content .section { - max-width: 100% -} - -.bd-content .section table { - display: block; - overflow: auto -} - -.bd-toc-link { - display: block; - padding: .25rem 1.5rem; - font-weight: 600; - color: rgba(0, 0, 0, .65) -} - -.bd-toc-link:hover { - color: rgba(0, 0, 0, .85); - text-decoration: none -} - -.bd-toc-item.active { - margin-bottom: 1rem -} - -.bd-toc-item.active:not(:first-child) { - margin-top: 1rem -} - -.bd-toc-item.active>.bd-toc-link { - color: rgba(0, 0, 0, .85) -} - -.bd-toc-item.active>.bd-toc-link:hover { - background-color: transparent -} - -.bd-toc-item.active>.bd-sidenav { - display: block -} - -nav.bd-links p.caption { - font-size: var(--pst-sidebar-caption-font-size); - text-transform: uppercase; - font-weight: 700; - position: relative; - margin-top: 1.25em; - margin-bottom: .5em; - padding: 0 1.5rem; - color: rgba(var(--pst-color-sidebar-caption), 1) -} - -nav.bd-links p.caption:first-child { - margin-top: 0 -} - -.bd-sidebar .nav { - font-size: var(--pst-sidebar-font-size) -} - -.bd-sidebar .nav ul { - list-style: none; - padding: 0 0 0 1.5rem -} - -.bd-sidebar .nav li>a { - display: block; - padding: .25rem 1.5rem; - color: rgba(var(--pst-color-sidebar-link), 1) -} - -.bd-sidebar .nav li>a:hover { - color: rgba(var(--pst-color-sidebar-link-hover), 1); - text-decoration: none; - background-color: transparent -} - -.bd-sidebar .nav li>a.reference.external:after { - font-family: Font Awesome\ 5 Free; - font-weight: 900; - content: "\f35d"; - font-size: .75em; - margin-left: .3em -} - -.bd-sidebar .nav .active:hover>a, -.bd-sidebar .nav .active>a { - font-weight: 600; - color: rgba(var(--pst-color-sidebar-link-active), 1) -} - -.toc-h2 { - font-size: .85rem -} - -.toc-h3 { - font-size: .75rem -} - -.toc-h4 { - font-size: .65rem -} - -.toc-entry>.nav-link.active { - font-weight: 600; - color: #130654; - color: rgba(var(--pst-color-toc-link-active), 1); - background-color: transparent; - border-left: 2px solid rgba(var(--pst-color-toc-link-active), 1) -} - -.nav-link:hover { - border-style: none -} - -#navbar-main-elements li.nav-item i { - font-size: .7rem; - padding-left: 2px; - vertical-align: middle -} - -.bd-toc .nav .nav, -.list-caption .nav { - display: none -} - -.bd-toc .nav .nav.visible, -.bd-toc .nav>.active>ul, -.list-caption .nav.visible, -.list-caption>.active>ul { - display: block -} - -.prev-next-area { - margin: 20px 0 -} - -.prev-next-area p { - margin: 0 .3em; - line-height: 1.3em -} - -.prev-next-area i { - font-size: 1.2em -} - -.prev-next-area a { - display: flex; - align-items: center; - border: none; - padding: 10px; - max-width: 45%; - overflow-x: hidden; - color: rgba(0, 0, 0, .65); - text-decoration: none -} - -.prev-next-area a p.prev-next-title { - color: rgba(var(--pst-color-link), 1); - font-weight: 600; - font-size: 1.1em -} - -.prev-next-area a:hover p.prev-next-title { - text-decoration: underline -} - -.prev-next-area a .prev-next-info { - flex-direction: column; - margin: 0 .5em -} - -.prev-next-area a .prev-next-info .prev-next-subtitle { - text-transform: capitalize -} - -.prev-next-area a.left-prev { - float: left -} - -.prev-next-area a.right-next { - float: right -} - -.prev-next-area a.right-next div.prev-next-info { - text-align: right -} - -.alert { - padding-bottom: 0 -} - -.alert-info a { - color: #e83e8c -} - -#navbar-icon-links i.fa, -#navbar-icon-links i.fab, -#navbar-icon-links i.far, -#navbar-icon-links i.fas { - vertical-align: middle; - font-style: normal; - font-size: 1.5rem; - line-height: 1.25 -} - -#navbar-icon-links i.fa-github-square:before { - color: #333 -} - -#navbar-icon-links i.fa-twitter-square:before { - color: #55acee -} - -#navbar-icon-links i.fa-gitlab:before { - color: #548 -} - -#navbar-icon-links i.fa-bitbucket:before { - color: #0052cc -} - -#navbar-icon-links img.icon-link-image { - height: 1.5em -} - -.tocsection { - border-left: 1px solid #eee; - padding: .3rem 1.5rem -} - -.tocsection i { - padding-right: .5rem -} - -.editthispage { - padding-top: 2rem -} - -.editthispage a { - color: var(--pst-color-sidebar-link-active) -} - -.xr-wrap[hidden] { - display: block !important -} - -.toctree-checkbox { - position: absolute; - display: none -} - -.toctree-checkbox~ul { - display: none -} - -.toctree-checkbox~label i { - transform: rotate(0deg) -} - -.toctree-checkbox:checked~ul { - display: block -} - -.toctree-checkbox:checked~label i { - transform: rotate(180deg) -} - -.bd-sidebar { - padding-top: 1em; - overflow-y: auto; - display: flex; - flex-direction: column -} - -@media (min-width:720px) { - .bd-sidebar { - border-right: 1px solid rgba(0, 0, 0, .1) - } - - @supports (position:-webkit-sticky) or (position:sticky) { - .bd-sidebar { - position: -webkit-sticky; - position: sticky; - top: var(--pst-header-height); - z-index: 1000; - height: calc(100vh - var(--pst-header-height)) - } - } -} - -.bd-sidebar.no-sidebar { - border-right: 0 -} - -.bd-sidebar .sidebar-end-items { - margin-top: auto; - margin-bottom: 1em -} - -.bd-sidebar .list-caption { - list-style: none; - padding-left: 0 -} - -.bd-sidebar li { - position: relative -} - -.bd-sidebar li.has-children>.reference { - padding-right: 30px -} - -.bd-sidebar label { - position: absolute; - top: 0; - right: 0; - height: 30px; - width: 30px; - cursor: pointer; - display: flex; - justify-content: center; - align-items: center -} - -.bd-sidebar label:hover { - background: rgba(var(--pst-color-sidebar-expander-background-hover), 1) -} - -.bd-sidebar label i { - display: inline-block; - font-size: .75rem; - text-align: center -} - -.bd-sidebar label i:hover { - color: rgba(var(--pst-color-sidebar-link-hover), 1) -} - -.bd-sidebar .label-parts { - width: 100%; - height: 100% -} - -.bd-sidebar .label-parts:hover { - background: none -} - -.bd-sidebar .label-parts i { - width: 30px; - position: absolute; - top: .3em; - right: 0 -} - -div.doctest>div.highlight span.gp, -span.linenos, -table.highlighttable td.linenos { - user-select: none; - -webkit-user-select: text; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none -} - -.docutils.container { - padding-left: unset; - padding-right: unset -} \ No newline at end of file diff --git a/doc/rst/_static/css/pygments-ecal-addon.css b/doc/rst/_static/css/pygments-ecal-addon.css deleted file mode 100644 index a951f173aa..0000000000 --- a/doc/rst/_static/css/pygments-ecal-addon.css +++ /dev/null @@ -1,6 +0,0 @@ -span.linenos { - color: inherit; - padding-left: 5px; - padding-right: 5px; - margin-right: 15px; -} \ No newline at end of file diff --git a/doc/rst/_static/css/sphinx-book-theme-1.1.2-ecaladdon.css b/doc/rst/_static/css/sphinx-book-theme-1.1.2-ecaladdon.css new file mode 100644 index 0000000000..0ff1c1d2c1 --- /dev/null +++ b/doc/rst/_static/css/sphinx-book-theme-1.1.2-ecaladdon.css @@ -0,0 +1,12 @@ +html[data-theme=dark], +html[data-theme=light] { + --pst-color-primary: #ffa500; +} + +html[data-theme=light] { + --pst-color-secondary: #CC8400; +} + +html[data-theme=dark] { + --pst-color-secondary: #FFC04D; +} \ No newline at end of file diff --git a/doc/rst/_static/css/tabs-3.4.5-ecaladdon.css b/doc/rst/_static/css/tabs-3.4.5-ecaladdon.css new file mode 100644 index 0000000000..07065503ea --- /dev/null +++ b/doc/rst/_static/css/tabs-3.4.5-ecaladdon.css @@ -0,0 +1,93 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0a0a0; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: var(--pst-color-muted); + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: var(--pst-color-background); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0a0a0; + border-bottom: 1px solid var(--pst-color-background); + margin: -1px; + background-color: var(--pst-color-background); + + box-shadow: 0 9px 0px -1px var(--pst-color-background), 0 3px 3px 0 var(--pst-color-shadow); +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0a0a0; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: var(--pst-color-background); + + box-shadow: 0 3px 3px 0px var(--pst-color-shadow); +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/doc/rst/_static/css/tabs.css b/doc/rst/_static/css/tabs.css deleted file mode 100644 index 2b626b0f9d..0000000000 --- a/doc/rst/_static/css/tabs.css +++ /dev/null @@ -1,55 +0,0 @@ -.sphinx-tabs { - margin-bottom: 1rem; -} - -[role="tablist"] { - border-bottom: 1px solid #a0a0a0; -} - -.sphinx-tabs-tab { - position: relative; - font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif; - color: #6b6b6b; - line-height: 24px; - margin: 0; - font-size: 16px; - font-weight: 400; - background-color: rgba(255, 255, 255, 0); - border-radius: 5px 5px 0 0; - border: 0; - padding: 1rem 1.5rem; - margin-bottom: 0; -} - -.sphinx-tabs-tab[aria-selected="true"] { - font-weight: 700; - border: 1px solid #a0a0a0; - border-bottom: 1px solid white; - margin-bottom: -1px; - background-color: white; - - box-shadow: 0 9px 0px -1px rgb(255, 255, 255, 255), 0 3px 3px 0 rgba(0, 0, 0, 0.2); -} - -.sphinx-tabs-tab:focus { - z-index: 1; -} - -.sphinx-tabs-panel { - position: relative; - padding: 1rem; - border: 1px solid #a0a0a0; - border-radius: 0 0 5px 5px; - border-top: 0; - background: white; - - box-shadow: 0 3px 3px 0px rgba(0, 0, 0, 0.2); -} - -.sphinx-tabs-panel.code-tab { - padding: 0.4rem; -} - -.sphinx-tab img { - margin-bottom: 24 px; -} diff --git a/doc/rst/_static/css/theme-ecal-addon.css b/doc/rst/_static/css/theme-ecal-addon.css deleted file mode 100644 index 1f0fc8ba59..0000000000 --- a/doc/rst/_static/css/theme-ecal-addon.css +++ /dev/null @@ -1,9 +0,0 @@ -:root { - --pst-color-active-navigation: 83, 56, 6; - --pst-color-navbar-link-hover: var(--pst-color-active-navigation); - --pst-color-navbar-link-active: var(--pst-color-active-navigation); - --pst-color-sidebar-link-hover: var(--pst-color-active-navigation); - --pst-color-sidebar-link-active: var(--pst-color-active-navigation); - --pst-color-toc-link-hover: var(--pst-color-active-navigation); - --pst-color-toc-link-active: var(--pst-color-active-navigation); -} diff --git a/doc/rst/_templates/footer copy.html b/doc/rst/_templates/footer copy.html new file mode 100644 index 0000000000..806c6e9df0 --- /dev/null +++ b/doc/rst/_templates/footer copy.html @@ -0,0 +1,18 @@ +
Eclipse Foundation
+ \ No newline at end of file diff --git a/doc/rst/_templates/footer.html b/doc/rst/_templates/footer.html new file mode 100644 index 0000000000..447ca399ff --- /dev/null +++ b/doc/rst/_templates/footer.html @@ -0,0 +1,26 @@ + + + diff --git a/doc/rst/advanced/ecal_in_docker.rst b/doc/rst/advanced/ecal_in_docker.rst index 39c8167e45..0b03698740 100644 --- a/doc/rst/advanced/ecal_in_docker.rst +++ b/doc/rst/advanced/ecal_in_docker.rst @@ -193,10 +193,10 @@ Seamless IPC-Communication across host borders .. important:: This will work with eCAL 5.12 and higher. - Older versions lack the ability to utilize the ``host_group_name`` in the :file:`ecal.ini` file, thus it won't work. + Older versions lack the ability to utilize the ``host_group_name`` in the :file:`ecal.yaml` file, thus it won't work. -In eCAL, you are able to set host belonging over network borders by utilizing the :file:`ecal.ini` configuration file with the same ``host_group_name`` - in the following steps, you will learn how to set this up. +In eCAL, you are able to set host belonging over network borders by utilizing the :file:`ecal.yaml` configuration file with the same ``host_group_name`` - in the following steps, you will learn how to set this up. .. note:: If we don't set the same ``host_group_name`` on our Host and our Containers, an IPC-Communication across host borders is not available with different host names. @@ -207,28 +207,28 @@ In eCAL, you are able to set host belonging over network borders by utilizing th sudo docker network create --driver=bridge --subnet=10.0.10.0/24 my_network -#. Edit your :file:`ecal.ini` and run your Container within the newly created docker network +#. Edit your :file:`ecal.yaml` and run your Container within the newly created docker network * You will use our previously discussed :ref:`ecal-runtime-image` for the next step. - * First, open :file:`/etc/ecal/ecal.ini` from your preferred editor. + * First, open :file:`/etc/ecal/ecal.yaml` from your preferred editor. - * Search for the line ``network_enabled`` and set it to ``true``. + * Search for the line ``registration->network_enabled`` and set it to ``true``. - * Search for the line ``host_group_name`` and write your preferred name. + * Search for the line ``registration->host_group_name`` and write your preferred name. - * Save and close the :file:`ecal.ini` file. + * Save and close the :file:`ecal.yaml` file. - * Now your :file:`ecal.ini` file is prepared. - We want to use it not only for our Host-System but also for our Container, so we don't need to edit the :file:`ecal.ini` in our Container again. + * Now your :file:`ecal.yaml` file is prepared. + We want to use it not only for our Host-System but also for our Container, so we don't need to edit the :file:`ecal.yaml` in our Container again. To achieve that, run following command to start your container: .. code-block:: bash - sudo docker run --rm -it --ipc=host --pid=host --network=my_network --name=container1 -h=container1 --ip=10.0.10.10 -v /etc/ecal/ecal.ini:/etc/ecal/ecal.ini ecal-runtime + sudo docker run --rm -it --ipc=host --pid=host --network=my_network --name=container1 -h=container1 --ip=10.0.10.10 -v /etc/ecal/ecal.yaml:/etc/ecal/ecal.yaml ecal-runtime - You should now be inside the root shell of your Container. - Check if your :file:`ecal.ini` file is correct. + Check if your :file:`ecal.yaml` file is correct. - Now your Container is prepared and configured correctly, so we are ready to start an eCAL example. diff --git a/doc/rst/advanced/layers/inproc.rst b/doc/rst/advanced/layers/inproc.rst deleted file mode 100644 index aa52ae3e4d..0000000000 --- a/doc/rst/advanced/layers/inproc.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. include:: /include.txt - -.. _transport_layer_inproc: - -======================== -eCAL Inner-Process Layer -======================== - -This section is still under construction. But we are working on it! Just be patient. - -.. image:: /img/snail.svg - :alt: Snail - :align: center diff --git a/doc/rst/advanced/layers/shm.rst b/doc/rst/advanced/layers/shm.rst index b43f0f8169..5ad1e038e9 100644 --- a/doc/rst/advanced/layers/shm.rst +++ b/doc/rst/advanced/layers/shm.rst @@ -51,16 +51,20 @@ To support one to many publisher/subscriber connections, the publisher creates o Configuration ============= -The SHM Layer is set to ``auto`` (= 2) by default. -This means, that it is used automatically for all messages that need to be transmitted inside a single host. +The SHM Layer is set to ``enable`` by default. -The system-configuration-parameters in the :file:`ecal.ini` are: +The system-configuration-parameters in the :file:`ecal.yaml` are: -.. code-block:: ini - - [publisher] - use_shm = 2 +.. code-block:: yaml + # Publisher specific base settings + publisher: + layer: + # Base configuration for shared memory publisher + shm: + # Enable layer + enable: true + [..] There are a few options for tweaking the communication. Those options are explained below. @@ -76,13 +80,20 @@ If subscribers are too slow to process incoming messages then the overall softwa There may still be cases where it could make sense to synchronize the transfer of the payload from a publisher to a subscriber by using an additional handshake event. This event is signaled by a subscriber back to the sending publisher to confirm the complete payload transmission. -The handshake mechanism can be activated in the :file:`ecal.ini`: +The handshake mechanism can be activated in the :file:`ecal.yaml`: -.. code-block:: ini +.. code-block:: yaml - [publisher] - ; activate synchronization via memory transfer acknowledge signal with a timeout of 100 milliseconds - memfile_ack_timeout = 100 + # Publisher specific base settings + publisher: + layer: + # Base configuration for shared memory publisher + shm: + [..] + # Force connected subscribers to send acknowledge event after processing the message. + # The publisher send call is blocked on this event with this timeout (0 == no handshake). + acknowledge_timeout_ms: 5 + [..] If the parameter is set to a non-zero timeout, the publisher will create an additional event and inform the subscriber to fire this event when the transmission of the payload is completed. @@ -147,12 +158,18 @@ You can activate the feature in the following ways. - **Use multi-buffering as system-default**: - Edit your :file:`ecal.ini` and set a buffer count greater than 1: + Edit your :file:`ecal.yaml` and set a buffer count greater than 1: - .. code-block:: ini + .. code-block:: yaml - [publisher] - memfile_buffer_count = 3 + # Publisher specific base settings + publisher: + layer: + # Base configuration for shared memory publisher + shm: + [..] + # Maximum number of used buffers (needs to be greater than 0, default = 1) + memfile_buffer_count: 3 - **Use multi-buffering for a single publisher (from your code):** @@ -160,11 +177,21 @@ You can activate the feature in the following ways. .. code-block:: cpp - // Create a publisher (topic name "person") - eCAL::protobuf::CPublisher pub("person"); + #include + + ... + + // Create a publisher configuration object + eCAL::Publisher::Configuration pub_config; + + // Set the option for buffer count in layer->shm->memfile_buffer_count to 3, so it will create 3 SHM files + pub_config.layer.shm.memfile_buffer_count = 3; + + // Create a publisher (topic name "person") and pass the configuration object + eCAL::protobuf::CPublisher pub("person", pub_config); + + ... - // Set multi-buffering to 3, so it will create 3 SHM files - pub.ShmSetBufferCount(3); Combining the zero-copy feature with an increased number of memory buffer files (like 2 or 3) could be a nice setup allowing the subscriber to work on the memory file content without copying its content and nevertheless not blocking the publisher to write new data. Using Multibuffering however will force each Send operation to re-write the entire memory file and disable partial updates. \ No newline at end of file diff --git a/doc/rst/advanced/layers/shm_zerocopy.rst b/doc/rst/advanced/layers/shm_zerocopy.rst index 3fc03b0b7f..20d922d5c6 100644 --- a/doc/rst/advanced/layers/shm_zerocopy.rst +++ b/doc/rst/advanced/layers/shm_zerocopy.rst @@ -20,24 +20,40 @@ Enabling eCAL Zero Copy - **Use zero-copy as system-default:** - Zero Copy can be enabled as system default from the :file:`ecal.ini` file like follows: + Zero Copy can be enabled as system default from the :file:`ecal.yaml` file like follows: - .. code-block:: ini + .. code-block:: yaml + + # Publisher specific base settings + publisher: + layer: + # Base configuration for shared memory publisher + shm: + [..] + # Enable zero copy shared memory transport mode + zero_copy_mode: true - [publisher] - memfile_zero_copy = 1 - **Use zero-copy for a single publisher (from your code):** - Zero-copy can be activated (or deactivated) for a single publisher from the eCAL API: + Zero-copy can be activated (or deactivated) for a single publisher by using a specific publisher configuration: .. code-block:: cpp + + #include + + ... + + // Create a publisher configuration object + eCAL::Publisher::Configuration pub_config; + + // Set the option for zero copy mode in layer->shm->zero_copy_mode to true + pub_config.layer.shm.zero_copy_mode = true; - // Create a publisher (topic name "person") - eCAL::protobuf::CPublisher pub("person"); + // Create a publisher (topic name "person") and pass the configuration object + eCAL::protobuf::CPublisher pub("person", pub_config); - // Enable zero-copy for this publisher - pub.ShmEnableZeroCopy(true); + ... Keep in mind, that using protobuf for serialization will still: @@ -292,16 +308,21 @@ To send this payload you just need a few lines of code: .. code-block:: cpp + #include + int main(int argc, char** argv) { // initialize eCAL API eCAL::Initialize(argc, argv, "binary_payload_snd"); - // publisher for topic "simple_struct" - eCAL::CPublisher pub("simple_struct"); + // Create a publisher configuration object + eCAL::Publisher::Configuration pub_config; - // turn zero copy mode on - pub.ShmEnableZeroCopy(true); + // Set the option for zero copy mode in layer->shm->zero_copy_mode to true + pub_config.layer.shm.zero_copy_mode = true; + + // publisher for topic "simple_struct" + eCAL::CPublisher pub("simple_struct", pub_config); // create the simple struct payload CStructPayload struct_payload; @@ -369,6 +390,6 @@ Default eCAL SHM vs. Full Zero Copy SHM Combining Zero Copy and Multibuffering ====================================== -For technical reasons the Full Zero Copy mode described above is turned of if the Multibuffering option ``CPublisher::ShmSetBufferCount`` is activated. +For technical reasons the Full Zero Copy mode described above is turned off if the Multibuffering option ``CPublisher::ShmSetBufferCount`` is activated. Default (subscriber side) Zero Copy is working in combination with Multibuffering as described. diff --git a/doc/rst/advanced/layers/tcp.rst b/doc/rst/advanced/layers/tcp.rst index 6f784c79d6..b284f69ccb 100644 --- a/doc/rst/advanced/layers/tcp.rst +++ b/doc/rst/advanced/layers/tcp.rst @@ -63,13 +63,28 @@ You can activate TCP in the following ways: #. **Use TCP as system default (only recommended for testing):** - Modify the :file:`ecal.ini` and change the following: - - .. code-block:: ini - - [publisher] - use_tcp = 2 - use_udp_mc = 0 + Modify the :file:`ecal.yaml` and change the following: + + .. code-block:: yaml + + # Publisher specific base settings + publisher: + layer: + # Base configuration for shared memory publisher + shm: + # Enable layer + enable: true + [..] + + # Base configuration for UDP publisher + udp: + # Enable layer + enable: false + + # Base configuration for TCP publisher + tcp: + # Enable layer + enable: true This will @@ -88,19 +103,27 @@ You can activate TCP in the following ways: .. code-block:: cpp - // Create a publisher (topic name "person") - eCAL::protobuf::CPublisher pub("person"); + #include + + ... - // Switch UDP Multicast layer off - pub.SetLayerMode(eCAL::TLayer::tlayer_udp_mc, eCAL::TLayer::smode_off); + // Create a publisher configuration object + eCAL::Publisher::Configuration pub_config; + + // Set enable shm and tcp, disable udp layer + pub_config.layer.shm.enable = true; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = true; + + // Create a publisher (topic name "person") and pass the configuration object + eCAL::protobuf::CPublisher pub("person"); - // Switch TCP layer on for Network connections (-> smode_uto) - pub.SetLayerMode(eCAL::TLayer::tlayer_tcp, eCAL::TLayer::smode_auto); + ... .. seealso:: Also see the ``person_snd_tcp`` sample: - https://github.com/eclipse-ecal/ecal/tree/master/samples/cpp/pubsub/protobuf/person_snd_tcp + https://github.com/eclipse-ecal/ecal/tree/master/ecal/samples/cpp/pubsub/protobuf/person_snd_tcp diff --git a/doc/rst/advanced/message_drops.rst b/doc/rst/advanced/message_drops.rst index ac3b6b3303..3e70da4ac8 100644 --- a/doc/rst/advanced/message_drops.rst +++ b/doc/rst/advanced/message_drops.rst @@ -32,7 +32,7 @@ Dropping on Transport Layer - Having different link speeds in your network will almost always cause many drops for large messages, as you are e.g. sending with 10 Gbit to a 1Gbit port and so 90% of all packages are dropped. This has to be viewed on a traffic-per-message-basis, not on a traffic-per-second basis. For instance, you may be sending only 1 message per second from a 10Gibt link. This message is maybe sent in 10ms, while the 1 Gbit link would need 100ms to receive all the data. Consequently, the 1Gbit connection will inevitably start dropping fragments, even though the network is not even close to its capacity. - You can work around it by just connecting everything with the same link-speed, and by using the ``bandwidth_max_udp`` setting from the :ref:`ecal.ini ` + You can work around it by just connecting everything with the same link-speed, and by using the ``bandwidth_max_udp`` setting from the :ref:`ecal.yaml ` - Larger eCAL Messages are more likely to be corrupt, as they consist of more fragments. diff --git a/doc/rst/advanced/src/ecal_in_docker/ecal_runtime_container/Dockerfile b/doc/rst/advanced/src/ecal_in_docker/ecal_runtime_container/Dockerfile index 4f158beaf7..5a4768bd15 100644 --- a/doc/rst/advanced/src/ecal_in_docker/ecal_runtime_container/Dockerfile +++ b/doc/rst/advanced/src/ecal_in_docker/ecal_runtime_container/Dockerfile @@ -12,11 +12,11 @@ RUN apt-get install -y ecal # You can omit this, if you don't want to build applications in the container. RUN apt-get install -y cmake g++ libprotobuf-dev protobuf-compiler -# Set network_enabled = true in ecal.ini. +# Set network_enabled = true in ecal.yaml. # You can omit this, if you only need local communication. -RUN awk -F"=" '/^network_enabled/{$2="= true"}1' /etc/ecal/ecal.ini > /etc/ecal/ecal.tmp && \ - rm /etc/ecal/ecal.ini && \ - mv /etc/ecal/ecal.tmp /etc/ecal/ecal.ini +RUN awk -F"=" '/^network_enabled/{$2="= true"}1' /etc/ecal/ecal.yaml > /etc/ecal/ecal.tmp && \ + rm /etc/ecal/ecal.yaml && \ + mv /etc/ecal/ecal.tmp /etc/ecal/ecal.yaml # Print the eCAL config RUN ecal_config \ No newline at end of file diff --git a/doc/rst/advanced/transport_layers.rst b/doc/rst/advanced/transport_layers.rst index 081578f0af..a517fecd30 100644 --- a/doc/rst/advanced/transport_layers.rst +++ b/doc/rst/advanced/transport_layers.rst @@ -14,7 +14,7 @@ eCAL distinguished between three types of communication: - **Interhost Communication**: communication between publishers / subscribers that are located on different hosts, inside a network .. note:: - Per default, interhost communication is turned off by configuration. To configure this you need to set the ecal.ini [network/network_enabled] parameter to true (network communication mode) or false (local host only communication mode) + Per default, interhost communication is turned off by configuration. To configure this you need to set the ecal.yaml [network/network_enabled] parameter to true (network communication mode) or false (local host only communication mode) In general the latency of the data transport increases depending on the "distance" of the communication participants. The "closer" the participants, the "quicker" the transport. @@ -35,8 +35,6 @@ Most of them can be configured additionally. +----------------------------------------------+--------------------------+--------------------+-------------------------------------------------------------------------------------------+ | Layer | ini parameter | Physical Layer | Comment | +==============================================+==========================+====================+===========================================================================================+ -| :ref:`inproc ` | [publisher/use_inproc] | inner process | inner process, zeroy copy communication (pointer forwarding) | -+----------------------------------------------+--------------------------+--------------------+-------------------------------------------------------------------------------------------+ | :ref:`shm ` | [publisher/use_shm] | shared memory | interprocess, shared memory communication, supports N:M connections, 2 memory copies | +----------------------------------------------+--------------------------+--------------------+-------------------------------------------------------------------------------------------+ | :ref:`udp_mc ` | [publisher/use_udp_mc] | udp multicast | interhost, topic name based dynamic multicast grouping to optimize pub/sub socket payload | @@ -50,15 +48,15 @@ Default transport layers Not all transport layers may be used for all communication scenarios, e.g. it's not possible to use shared memory transport on interhost communication. eCAL provides sensible default transport methods, depending on the type of communication taking place. -+-----------------------------+------------+-----------+------------+------------+ -| Header 1 | inproc | shm | udp_mc | tcp | -+=============================+============+===========+============+============+ -| Intraprocess Communication | available | default | available | available | -+-----------------------------+------------+-----------+------------+------------+ -| Interprocess Communication | | default | available | available | -+-----------------------------+------------+-----------+------------+------------+ -| Interhost Communication | | | default | available | -+-----------------------------+------------+-----------+------------+------------+ ++-----------------------------+-----------+------------+------------+ +| Header 1 | shm | udp_mc | tcp | ++=============================+===========+============+============+ +| Intraprocess Communication | default | available | available | ++-----------------------------+-----------+------------+------------+ +| Interprocess Communication | default | available | available | ++-----------------------------+-----------+------------+------------+ +| Interhost Communication | | default | available | ++-----------------------------+-----------+------------+------------+ Configuration of transport layers @@ -67,25 +65,23 @@ Configuration of transport layers In case the default configuration is not sensible enough, the eCAL user can finetune the configuration. The layers can be set up -- for a whole machine using the central configuration file (ecal.ini) +- for a whole machine using the central configuration file (ecal.yaml) - for a single eCAL process passed by command line arguments - for a single publish-subscribe connection using the C++ or python publisher API. -Every layer can set up in 3 different activation modes. Every mode can be configured as default in the ecal.ini file and can be overwritten by the C++/Python publisher API. This is the activation logic +Every layer can set up in 3 different activation modes. Every mode can be configured as default in the ecal.yaml file and can be overwritten by the C++/Python publisher API. This is the activation logic - off: layer is switched off - on: layer is always switched on (i.e. payload will be send no matter if there is any local or network subscription) - auto: layer will be switched on automatically - - inproc = 2 : layer used automatically for inner process subscribers - shm = 2 : layer used automatically for inter process subscribers - udp_mc = 2 : layer used automatically for inter host (network) subscribers Independent from this publisher setting you can switch on/off the receiving (subscription) logic for every layer. That means you can prevent incoming payload on specific layers. -This can be done in the ecal.ini file [network] section. +This can be done in the ecal.yaml file [network] section. -- inproc_rec_enabled = true / false : enable / disable inner process subscriptions - shm_rec_enabled = true / false : enable / disable inter process subscriptions - udp_mc_rec_enabled = true / false : enable / disable inter host subscriptions @@ -97,4 +93,3 @@ This can be done in the ecal.ini file [network] section. layers/shm.rst layers/udp_mc.rst layers/tcp.rst - layers/inproc.rst diff --git a/doc/rst/applications/sys/sys_gui.rst b/doc/rst/applications/sys/sys_gui.rst index d82824995b..dbff603b30 100644 --- a/doc/rst/applications/sys/sys_gui.rst +++ b/doc/rst/applications/sys/sys_gui.rst @@ -86,7 +86,7 @@ Task configuration Whether the window of the started task shall be normal, maximized or minimized. Only supported on Microsoft Windows. - When using a terminal emulator on linux (see :ref:`ecal.ini`), the option *minimized* will prevent opening a terminal emulator and the process will print its output in the ecal_sys_client terminal as usual. + When using a terminal emulator on linux (see :ref:`ecal.yaml`), the option *minimized* will prevent opening a terminal emulator and the process will print its output in the ecal_sys_client terminal as usual. - **Launch order**: Defines the order of tasks that must be started serialized. diff --git a/doc/rst/conf.py b/doc/rst/conf.py index 02b9ebc0e8..48b812bee6 100644 --- a/doc/rst/conf.py +++ b/doc/rst/conf.py @@ -77,10 +77,16 @@ #author = u'Continental' # The short X.Y version -version = u'' +# version = u'' # The full version, including alpha/beta/rc tags -release = u'' +# Get release version from ECAL_DOC_VERSION environment variable +ecal_doc_version = os.getenv("ECAL_DOC_VERSION") + +if not ecal_doc_version: + ecal_doc_version = "" + +release = ecal_doc_version # The release variable is important for the version-banner # -- General configuration --------------------------------------------------- @@ -187,22 +193,10 @@ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] - -# Original hirarchy: -# 1. theme.css -# 2. pydata-sphinx-theme.css -# 3. all.min.css -# 4. pygments.css -# 5. sphinx-book-theme.css -# 6. tabs.css html_css_files = [ - 'css/theme-ecal-addon.css', # Override some colors of theme.css (-> Addon) - 'css/pydata-ecal.css', # Replace entire pydata-sphinx-theme.css with custom one (created by python script) - 'css/pydata-ecal-addon.css', # Override some colors of the custom pydata-ecal.css again (-> Addon) - 'css/book-ecal-addon.css', # Override some size values of sphinx-book-theme.css (-> Addon) - 'css/bignums.css', # Enable th bignum feature from the sphinx-typo3-theme - 'css/tabs.css', # Custom styling for sphinx-tabs - 'css/pygments-ecal-addon.css', # Override some sizes of pygments.css (-> Addon) + 'css/bignums.css', # Enable the bignum feature from the sphinx-typo3-theme + 'css/sphinx-book-theme-1.1.2-ecaladdon.css', # Change colors of the sphinx-book-theme + 'css/tabs-3.4.5-ecaladdon.css', # Change colors of the sphinx-tabs ] html_title = "Eclipse eCAL™" @@ -220,24 +214,25 @@ "repository_branch": "master", "path_to_docs": "doc/rst/", "extra_navbar": "", # => Remove the default text - "extra_footer": '
Eclipse Foundation
' - '', + "footer_start": ["footer.html"], + "extra_footer": '', + + # Add version switcher to choose between different versions of the documentation + "switcher": { + "json_url": "https://eclipse-ecal.github.io/ecal/switcher.json", + "version_match": ecal_doc_version, + }, + + # Set to check_switcher false to allow offline builds + "check_switcher": False, + + # Enable a banner telling the user that they look at an outdated version of the documentation + "show_version_warning_banner": True, +} + +html_sidebars = { + # Add the version switchter to the sidebar + "**": ["navbar-logo", "icon-links", "version-switcher", "search-field", "sbt-sidebar-nav.html"] } # -- Options for HTMLHelp output --------------------------------------------- diff --git a/doc/rst/configuration.rst b/doc/rst/configuration.rst index 1b169bb224..3c361e3db9 100644 --- a/doc/rst/configuration.rst +++ b/doc/rst/configuration.rst @@ -14,3 +14,4 @@ Configuration configuration/npcap configuration/player configuration/options + configuration/runtime_configuration diff --git a/doc/rst/configuration/cloud.rst b/doc/rst/configuration/cloud.rst index 0cf0b6ef68..de431e11b0 100644 --- a/doc/rst/configuration/cloud.rst +++ b/doc/rst/configuration/cloud.rst @@ -6,16 +6,31 @@ Cloud Configuration =================== -To switch eCAL to cloud mode, edit your :file:`ecal.ini` and change the following settings: +To switch eCAL to cloud mode, edit your :file:`ecal.yaml` and change the following settings: * |fa-windows| Windows: |ecalini-path-windows| * |fa-ubuntu| Ubuntu: |ecalini-path-ubuntu| -.. code-block:: ini - - [network] - network_enabled = true - multicast_ttl = 2 +.. code-block:: yaml + + # Registration layer configuration + registration: + [..] + # true = all eCAL components communicate over network boundaries + # false = local host only communication (Default: false) + network_enabled: true + + [..] + + # Transport layer configuration + transport_layer: + udp: + [..] + + network: + [..] + # TTL (hop limit) is used to determine the amount of routers being traversed towards the destination + ttl: 3 .. important:: Don't forget to set your multicast routes and make sure your hostname resolution works on all machines! diff --git a/doc/rst/configuration/local.rst b/doc/rst/configuration/local.rst index 83cc602fd3..4d2b1632ef 100644 --- a/doc/rst/configuration/local.rst +++ b/doc/rst/configuration/local.rst @@ -6,21 +6,36 @@ Local configuration =================== -Using eCAL in local mode can be benefitial +Using eCAL in local mode can be beneficial * to avoid network congestion if the data is not needed on other machines * to make eCAL work in VPN and Firewall scenarios where non-local traffic is blocked -To switch eCAL to local mode, edit your :file:`ecal.ini` and change the following settings: +To switch eCAL to local mode, edit your :file:`ecal.yaml` and change the following settings: * |fa-windows| Windows: |ecalini-path-windows| * |fa-ubuntu| Ubuntu: |ecalini-path-ubuntu| -.. code-block:: ini +.. code-block:: yaml - [network] - network_enabled = false - multicast_ttl = 0 + # Registration layer configuration + registration: + [..] + # true = all eCAL components communicate over network boundaries + # false = local host only communication (Default: false) + network_enabled: false + + [..] + + # Transport layer configuration + transport_layer: + udp: + [..] + + network: + [..] + # TTL (hop limit) is used to determine the amount of routers being traversed towards the destination + ttl: 0 .. seealso:: To learn about the differences between local mode and cloud mode, check out :ref:`this table `. \ No newline at end of file diff --git a/doc/rst/configuration/npcap.rst b/doc/rst/configuration/npcap.rst index f2d493ceb4..377f880682 100644 --- a/doc/rst/configuration/npcap.rst +++ b/doc/rst/configuration/npcap.rst @@ -39,9 +39,14 @@ How to use Npcap #. Edit |ecalini-path-windows|: - .. code-block:: ini + .. code-block:: yaml - npcap_enabled = true + # Transport layer configuration + transport_layer: + udp: + [..] + # Windows specific setting to enable receiving UDP traffic with the Npcap based receiver + npcap_enabled: true #. Check eCAL Mon diff --git a/doc/rst/configuration/options.rst b/doc/rst/configuration/options.rst index dfb49e97c7..8abcdfa7e6 100644 --- a/doc/rst/configuration/options.rst +++ b/doc/rst/configuration/options.rst @@ -3,7 +3,7 @@ .. _configuration_options: ======== -ecal.ini +ecal.yaml ======== eCAL has many options that can be configured via an .ini file which is located at: @@ -15,294 +15,496 @@ Loading strategy (Priority) =========================== The eCAL configuration file is loaded based on the following priorities, whereever it is found first. -If you want a specific eCAL Node to run with another ``ecal.ini`` than the others, you can set the ``ECAL_DATA`` variable before starting the process, e.g. from a batch or shell skript. -In addition, some eCAL applications support providing a path from the command line option ``--ecal-ini-file``. +If you want a specific eCAL Node to run with another ``ecal.yaml`` than the others, you can set the ``ECAL_DATA`` variable before starting the process, e.g. from a batch or shell skript. +In addition, some eCAL applications support providing a path from the command line option ``--ecal-config-file``. .. important:: This loading strategy is valid for eCAL 5.10 and up. - |fa-windows| Windows: - 1. ``%ECAL_DATA%/ecal.ini`` - 2. ``%ProgramData%/ecal/ecal.ini`` + 1. ``%ECAL_DATA%/ecal.yaml`` + 2. ``%ProgramData%/ecal/ecal.yaml`` - |fa-ubuntu| Ubuntu: - 1. ``$ECAL_DATA/ecal.ini`` - 2. ``/etc/ecal/ecal.ini`` (from ``CMAKE_INSTALL_SYSCONFDIR``) - 3. ``/etc/ecal/ecal.ini`` (fallback) + 1. ``$ECAL_DATA/ecal.yaml`` + 2. ``/etc/ecal/ecal.yaml`` (from ``CMAKE_INSTALL_SYSCONFDIR``) + 3. ``/etc/ecal/ecal.yaml`` (fallback) .. note:: - This second path is set from CMake to ``CMAKE_INSTALL_SYSCONFDIR/ecal/ecal.ini``. + This second path is set from CMake to ``CMAKE_INSTALL_SYSCONFDIR/ecal/ecal.yaml``. Official builds are configured to use ``/etc``. - If you are compiling eCAL yourself and don't provide the SYSCONFDIR, CMake will usually use ``/usr/local/etc/ecal/ecal.ini``. + If you are compiling eCAL yourself and don't provide the SYSCONFDIR, CMake will usually use ``/usr/local/etc/ecal/ecal.yaml``. -ecal.ini options -================ +ecal.yaml options +================= -[network] ---------- +Registration settings are listed in the section ``registration`` +---------------------------------------------------------------- -The network setting drive how and which ... +.. option:: registration -.. option:: network_enabled + .. option:: registration_refresh - ``true`` / ``false``, default: ``true`` - - ``true`` = all eCAL components communicate over network boundaries - - ``false`` = local host only communication - -.. option:: multicast_config_version + ``< registration_timeout/2``, default ``1000`` - ``v1`` / ``v2``, default: ``v1`` + topic registration refresh cycle (has to be smaller than registration timeout!) - UDP configuration version (Since eCAL 5.12.) - - ``v1`` = default behavior + .. option:: registration_timeout + + ``1000 + (x * 1000)``, default ``60000`` - ``v2`` = new behavior, comes with a bit more intuitive handling regarding masking of the groups + timeout for topic registration in ms -.. option:: multicast_group + .. option:: loopback - IPV4 Adress, default ``239.0.0.1`` + ``true`` / ``false``, default ``true`` + + enable to receive registration information on the same local machine - UDP multicast group base. All registration and logging information is sent on this address. + .. option:: shm_transport_domain -.. option:: multicast_mask + ````, default ``""`` - ``v1`` **behavior:** - - ``0.0.0.1``-``0.0.0.255`` + shm transport domain that enables interprocess mechanisms across (virtual) host borders (e.g. Docker); + by default equivalent to local host name - Mask maximum number of dynamic multicast group + .. option:: network_enabled - ``v2`` **behavior:** - - ``255.0.0.0``-``255.255.255.255`` - - Mask for the multicast group. Topic traffic may be set on any of the unmasked addresses. - - With ``multicast_group``: ``239.0.0.1`` and ``multicast_mask``: ``255.255.255.0``, topic traffic will be sent on addresses ``239.0.0.0``-``239.0.0.255``. - -.. option:: multicast_port - - ``14000 + x`` + ``true`` / ``false``, default: ``true`` + + ``true`` = all eCAL components communicate over network boundaries + + ``false`` = local host only communication - UDP multicast port number (eCAL will use at least the 2 following port numbers too, so please modify in steps of 10 (e.g. 1010, 1020 ...) + .. option:: layer -.. option:: multicast_ttl - - ``0 + x`` - - UDP ttl value, also known as hop limit, is used in determining the intermediate routers being traversed towards the destination + .. option:: shm + + .. option:: enabled -.. option:: multicast_sndbuf - - ``1024 * x`` - - UDP send buffer in bytes + ``true`` / ``false``, default: ``false`` -.. option:: multicast_rcvbuf - - ``1024 * x`` + enable shared memory layer - UDP receive buffer in bytes + .. option:: domain -.. option:: bandwidth_max_udp - - ``1048576`` - - UDP bandwidth limit for eCAL udp layer (-1 == unlimited) + ``ecal_mon`` -.. option:: inproc_rec_enabled - - ``true`` + Domain name for shared momory based registration - Enable to receive on eCAL inner process layer + .. option:: queue_size -.. option:: shm_rec_enabled + ``1024`` - ``true`` + Queue size of registration events - Enable to receive on eCAL shared memory layer + .. option:: udp + + .. option:: enabled + + ``true`` / ``false``, default: ``true`` + + enable UDP multicast layer + + .. option:: port + + ``14000 + x`` + + UDP port for registration information if UDP is enabled + + +Monitoring settings are listed in the section ``monitoring`` +---------------------------------------------------------- + +.. option:: monitoring + + .. option:: timeout + + ``1000 + (x * 1000)`` default ``1000`` + Timeout for topic monitoring in ms + If no additional registration information for the topic has be received in that time period, topics will no longer be shown in eCAL Monitor. + + + .. option:: filter_excl + + topics blacklist as regular expression (will not be monitored) + Per default includes all eCAL internal topics. + + default = ``^__.*$`` + + .. option:: filter_incl + + topics whitelist as regular expression (will be monitored only) + + default = `` `` + + +Transportlayer settings are listed in the section ``transport_layer`` +--------------------------------------------------------------------- + +.. option:: transport_layer + + .. option:: udp + + .. option:: config_version + + ``v1`` / ``v2``, default: ``v2`` + + UDP configuration version (Since eCAL 5.12.) + + ``v1`` = default behavior + + ``v2`` = new behavior, comes with a bit more intuitive handling regarding masking of the groups + + .. option:: mode + + ``local`` / ``network``, default: ``local`` + + ``local`` = use local network settings - not configurable by the user + + ``network`` = use network settings - configurable by the user + + .. option:: port + + ``14000 + x`` + + UDP multicast port number + + .. option:: mask + + ``v1`` **behavior:** + + ``0.0.0.1``-``0.0.0.255`` + + Mask maximum number of dynamic multicast group + + ``v2`` **behavior:** + + ``255.0.0.0``-``255.255.255.255`` + + Mask for the multicast group. Topic traffic may be set on any of the unmasked addresses. + + With ``group``: ``239.0.0.1`` and ``mask``: ``255.255.255.0``, topic traffic will be sent on addresses ``239.0.0.0``-``239.0.0.255``. + + .. option:: send_buffer + + ``1024 * x`` default ``5242880`` + + UDP send buffer in bytes + + .. option:: receive_buffer + + ``1024 * x`` default ``5242880`` + + UDP receive buffer in bytes + + .. option:: join_all_interfaces + + ``true`` / ``false`` default ``false`` + + Linux specific setting to join all network interfaces independend of their link state. + Enabling ensures that eCAL processes receive data when they are started before the + network devices are up and running. + + .. option:: npcap_enabled + + ``true`` / ``false`` default ``false`` + + Enable to receive UDP traffic with the Npcap based receiver + + .. option:: local + + In local mode the UDP multicast group is set to the local host address ("127.0.0.1") and the multicast TTL is set to 0 by default. + This is not configurable. + + .. option:: network + + .. option:: group + + ``xxx.xxx.xxx.xxx`` IP address as text, default ``239.0.0.1`` + + Multicast group base: all registration and logging is sent on this address + + .. option:: ttl + + ``0 + x`` default ``3`` + + TTL (hop limit) is used to determine the amount of routers being traversed towards the destination + + .. option:: tcp + + .. option:: number_executor_reader + + ``1 + x`` default ``1`` + + Number of reader threads that shall execute workload + + .. option:: number_executor_writer + + ``1 + x`` default ``1`` + + Number of writer threads that shall execute workload + + .. option:: max_reconnections + + ``1 + x`` default ``1`` + + Reconnection attemps the session will try to reconnect in case of an issue + + +Publisher settings are listed in the section ``publisher`` +---------------------------------------------------------- + +.. option:: publisher + + .. option:: layer + + .. option:: shm + + .. option:: enable + + ``true`` / ``false`` default ``true`` + + Enable shared memory layer -.. option:: udp_mc_rec_enabled - - ``true`` + .. option:: zero_copy_mode - Enable to receive on eCAL udp multicast layer + ``true`` / ``false`` default ``false`` -.. option:: npcap_enabled - - ``false`` - - Enable to receive UDP traffic with the Npcap based receiver + Enable zero copy mode for shared memory transport mode + .. option:: acknowledge_timeout_ms -[common] --------- + ``0 + x`` default ``0`` -.. option:: registration_timeout - - ``1000 + (x * 1000)``, default ``60000`` + Force connected subscribers to send acknowledge event after processing the message. + The publisher send call is blocked on this event with this timeout (0 == no handshake). - timeout for topic registration in ms + .. option:: memfile_buffer_count -.. option:: registration_refresh + ``1 + x`` default ``1`` - ``< registration_timeout/2``, default ``1000`` + Maximum number of used buffers (needs to be greater than 0, default = 1) - topic registration refresh cylce (has to be smaller then registration timeout !) + .. option:: memfile_min_size_bytes + + ``x * 4096 kB`` default ``4096`` + + Default memory file size for new publisher + + .. option:: memfile_reserve_percent -[time] ------- + ``20 .. x`` default ``50`` + + Dynamic file size reserve before recreating memory file if topic size changes -.. option:: timesync_module_rt - - default: ``"ecaltime-localtime"`` - - module (dll / so) name time sync interface. The name will be extended with debug suffix (d) and platform extension (.dll|.so) + .. option:: udp + + .. option:: enable + + ``true`` / ``false`` default ``true`` + + Enable UDP multicast layer + + .. option:: tcp + + .. option:: enable + + ``true`` / ``false`` default ``false`` + + Enable TCP layer + + .. option:: share_topic_type + + ``true`` / ``false`` default ``true`` + + Share topic type via registration layer + + + + .. option:: share_topic_description + + ``true`` / ``false`` default ``true`` + + Share topic description via registration layer. + If set to false, reflection is completely disabled. It is not possible then to monitor the content of messages in the eCAL Monitor. + + .. option:: priority_local + + ``["shm", "udp", "tcp"]`` default ``["shm", "udp", "tcp"]`` + + A list of transport layers as text that specifies the prioritized layer for local communication. + + .. option:: priority_remote + + ``["udp", "tcp"]`` default ``["udp", "tcp"]`` + + A list of transport layers as text that specifies the prioritized layer for remote communication. + + +Subscriber settings are listed in the section ``subscriber`` +------------------------------------------------------------ + +.. option:: subscriber + + .. option:: layer + + .. option:: shm + + .. option:: enable + + ``true`` / ``false`` default ``true`` + + Enable shared memory layer + + .. option:: udp + + .. option:: enable + + ``true`` / ``false`` default ``true`` + + Enable UDP multicast layer + + .. option:: tcp + + .. option:: enable + + ``true`` / ``false`` default ``false`` + + Enable TCP layer - Available modules are: - - - ecaltime-localtime local system time without synchronization - - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux (device configuration in ecaltime.ini) - - ecaltime-simtime Simulation time as published by the eCAL Player. + .. option:: drop_out_of_order_messages -[process] ---------- + ``true`` / ``false`` default ``false`` + + Enable dropping of payload messages that arrive out of order -.. _ecalini_option_terminal_emulator: -.. option:: terminal_emulator - - default: ``""`` +Time settings are listed in the section ``time`` +------------------------------------------------ - command for starting applications with an external terminal emulator. - If empty, the command will be ignored. - Ignored on Windows. - - e.g: +.. option:: time - - ``/usr/bin/x-terminal-emulator -e`` - - ``/usr/bin/gnome-terminal -x`` - - ``/usr/bin/xterm -e`` + .. option:: rt + + default: ``"ecaltime-localtime"`` + + Module (dll / so) name time sync interface. The name will be extended with debug suffix (d) and platform extension (.dll|.so) -[publisher] ------------ + Available modules are: + + - ecaltime-localtime local system time without synchronization + - ecaltime-linuxptp For PTP / gPTP synchronization over ethernet on Linux (device configuration in ecaltime.ini) + - ecaltime-simtime Simulation time as published by the eCAL Player. -.. option:: use_inproc - - use inner process transport layer - - - 0 = off - - 1 = on - - 2 = auto - - default = 0 - -.. option:: use_shm - - use shared memory transport layer - - - 0 = off - - 1 = on - - 2 = auto - - default = 2 - -.. option:: use_udp_mc - - use udp multicast transport layer - - - 0 = off - - 1 = on - - 2 = auto - - default = 2 - + .. option:: replay + default ``""`` -.. option:: memfile_minsize = x * 4096 kB - - default memory file size for new publisher (``x * 4096 kB``) - - default = 4096 + Module name of time plugin for replaying -.. option:: memfile_reserve - dynamic file size reserve before recreating memory file if topic size changes (``20 .. x``) +Service settings are listed in the section ``service`` +------------------------------------------------------ - default = 50 +.. option:: service -.. option:: memfile_ack_timeout + .. option:: protocol_v0 + + ``true`` / ``false`` default ``true`` - Publisher timeout for ack event from subscriber that memory file content is processed - - default = 0 + Support service protocol v0, eCAL 5.11 and older -.. option:: share_ttype + .. option:: protocol_v1 + + ``true`` / ``false`` default ``false`` - share topic type via registration layer ( ``0, 1``) + Support service protocol v1, eCAL 5.12 and newer - default = 1 -.. option:: share_tdesc +Application settings are listed in the section ``application`` +-------------------------------------------------------------- - share topic description via registration layer ( ``0, 1``) - If set to 0, reflection is completely disabled. It is not possible then to monitor the content of messages in the eCAL Monitor. - - default = 1 - -[monitoring] ------------- - -Monitor settings are listed in the section ``monitoring`` - -.. option:: timeout +.. option::application + + .. option:: sys + + .. option:: filter_excl + + Text as regex, default ``"^eCALSysClient$|^eCALSysGUI$|^eCALSys$*"`` + + Apps blacklist to be excluded when importing tasks from cloud. + + .. option:: terminal + + .. option:: emulator + + External terminal emulator as text, default ``""`` + + Linux only command for starting applications with an external terminal emulator. + e.g. + /usr/bin/x-terminal-emulator -e + /usr/bin/gnome-terminal -x + /usr/bin/xterm -e + + If empty, the command will be ignored. + + +Logging settings are listed in the section ``logging`` +------------------------------------------------------ + +.. option:: logging + + .. option:: sinks + + Log levels are: "info", "warning", "error", "fatal", "debug1", "debug2", "debug3", "debug4" + + .. option:: console + + .. option:: enable - timeout for topic monitoring in ms (``1000 + (x * 1000)``) - If no additional registration information for the topic has be received in that time period, topics will no longer be shown in eCAL Monitor. - - default = 5000 - -.. option:: filter_excl - - topics blacklist as regular expression (will not be monitored) - Per default includes all eCAL internal topics. - - default = ``^__.*$`` - -.. option:: filter_incl - - topics whitelist as regular expression (will be monitored only) - - default = `` `` - -.. option:: filter_log_con - - log messages to console (all, info, warning, error, fatal, debug1, debug2, debug3, debug4) - - default = ``error, fatal`` - -.. option:: filter_log_file - - log messages to log file - - default = ``error, fatal`` - -.. option:: filter_log_udp - - log messages to udp bus - - default = ``info, warning, error, fatal`` - -[sys] ------ - -.. option:: filter_excl - - Apps blacklist to be excluded when importing tasks from cloud. + ``true`` / ``false`` default ``false`` + + Enable console logging + + .. option:: level + + List of log levels as text, default ``["info", "warning", "error", "fatal"]`` + + .. option:: file + + .. option:: enable + + ``true`` / ``false`` default ``false`` + + Enable file logging + + .. option:: level + + List of log levels as text, default ``[]`` + + .. option:: path + + Path as text, default ``ecal.log`` + + .. option:: udp + + .. option:: enable + + ``true`` / ``false`` default ``false`` + + Enable udp logging + + .. option:: level + + List of log levels as text, default ``["info", "warning", "error", "fatal"]`` + + .. option:: port + + ``14000 + x`` default ``14001`` + + UDP port for logging information diff --git a/doc/rst/configuration/runtime_configuration.rst b/doc/rst/configuration/runtime_configuration.rst new file mode 100644 index 0000000000..08ed8f0a88 --- /dev/null +++ b/doc/rst/configuration/runtime_configuration.rst @@ -0,0 +1,57 @@ +.. include:: /include.txt + +.. _configuration_runtime_configuration: + +===================== +Runtime configuration +===================== + +eCAL provides an interface to access and modify its options before initialization. +The corresponding structure reflects the configuration file (:ref:`configuration_options`). + +Custom types +============ + +In order to rule out configuration errors, a custom datatype for IP addresses (IpAddressV4) is introduced. + +**IpAddressV4:** For assigning an IP address simply assign a string with the desired address. +Decimal and hexadecimal format is supported. +In case the IP address is not valid, the type will throw a std::invalid_argument exception. + +The IP address can be used like a normal string object. For example: + +.. code-block:: c++ + + eCAL::Types::IpAddressV4 ip_address = "192.168.7.1"; // in hex: "C0.A8.7.1" + std::cout << ip_address << "\n"; + + +Global configuration initialization +=================================== + +The configuration will be first initialized with the default values specified by eCAL. +If you want to use the systems eCAL .yaml file, call the ``InitFromConfig()`` function of the config object. + +In case the .yaml to use is specified via command line parameter, this one is chosen instead. +The object will throw an error, in case the specified .yaml file cannot be found. + +It is also possible to specify the .yaml by calling the function ``InitFromFile(const std::string yaml_path_)`` of the config object. + +* |fa-file-alt| :file:`hello_config/main.cpp`: + + .. literalinclude:: src/hello_config/main.cpp + :language: cpp + :linenos: + +Individual publisher/subscriber configuration +============================================= + +Like a global configuration to pass at initialization, it is also possible to create indiviual configurations for publisher and subscriber. +That means it is possible to, e.g., create two publisher which send on different transport layers: + +* |fa-file-alt| :file:`publisher/main.cpp`: + + .. literalinclude:: src/publisher_config/main.cpp + :language: cpp + :linenos: + diff --git a/doc/rst/configuration/src/hello_config/CMakeLists.txt b/doc/rst/configuration/src/hello_config/CMakeLists.txt new file mode 100644 index 0000000000..dd21b4264e --- /dev/null +++ b/doc/rst/configuration/src/hello_config/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0) +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) + +project(hello_config) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(eCAL REQUIRED) + +set(source_files + main.cpp +) + +add_executable(${PROJECT_NAME} ${source_files}) + +target_link_libraries(${PROJECT_NAME} + eCAL::core +) \ No newline at end of file diff --git a/doc/rst/configuration/src/hello_config/main.cpp b/doc/rst/configuration/src/hello_config/main.cpp new file mode 100644 index 0000000000..de201d202e --- /dev/null +++ b/doc/rst/configuration/src/hello_config/main.cpp @@ -0,0 +1,46 @@ +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + // Create a configuration object with the command line arguments + eCAL::Configuration custom_config(argc, argv); + + // Use the .yaml file of the system or current folder if available + custom_config.InitFromConfig(); + + // Set the values in a try/catch block, as wrong configuration leads to exceptions + try + { + // In case you decided to specify an own .yaml file to use + // Configuration based on previous ini file will be overwritten + custom_config.InitFromFile("C:\\eCAL_local.yaml"); + + // Set the communication layer to network + custom_config.registration.network_enabled = true; + + // Set a custom udp multicast group, correct IP address necessary + custom_config.transport_layer.udp.network.group = std::string("239.0.1.1"); + + // Increase the send buffer, size increase in 1024 bytes steps + custom_config.transport_layer.udp.send_buffer = (5242880 + 10 * 1024); + } + catch (std::invalid_argument& e) + { + throw std::runtime_error("Error while configuring eCALConfig: " + std::string(e.what())); + } + + // Initialize eCAL with the prepared configuration object + eCAL::Initialize(custom_config, "UserConfigExample", eCAL::Init::Default); + + // ... + // Use eCAL for your needs + // ... + + // Finalize eCAL API + eCAL::Finalize(); + + return 0; +} \ No newline at end of file diff --git a/doc/rst/configuration/src/publisher_config/CMakeLists.txt b/doc/rst/configuration/src/publisher_config/CMakeLists.txt new file mode 100644 index 0000000000..53f8f8fc47 --- /dev/null +++ b/doc/rst/configuration/src/publisher_config/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.0) +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) + +project(publisher_config) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(eCAL REQUIRED) + +set(source_files + main.cpp +) + +add_executable(${PROJECT_NAME} ${source_files}) + +target_link_libraries(${PROJECT_NAME} + eCAL::core +) \ No newline at end of file diff --git a/doc/rst/configuration/src/publisher_config/main.cpp b/doc/rst/configuration/src/publisher_config/main.cpp new file mode 100644 index 0000000000..d601f26d91 --- /dev/null +++ b/doc/rst/configuration/src/publisher_config/main.cpp @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + // initialize eCAL API + eCAL::Initialize("PublisherConfig", eCAL::Init::All); + + // create publisher config + eCAL::Publisher::Configuration pub_config; + + // disable all layers except for SHM + pub_config.layer.shm.enable = true; + pub_config.layer.udp.enable = false; + pub_config.layer.tcp.enable = false; + + // create publisher 1 + eCAL::string::CPublisher pub_1("topic_1", pub_config); + + // enable for the second publisher also tcp + pub_config.layer.tcp.enable = true; + + // create publisher 2 + eCAL::string::CPublisher pub_2("topic_2", pub_config); + + int counter {0}; + while (eCAL::Ok()) + { + std::string msg = "Send message number: " + std::to_string(counter++); + + // send message + pub_1.Send(msg); + pub_2.Send(msg); + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + // finalize eCAL API + eCAL::Finalize(); +} \ No newline at end of file diff --git a/doc/rst/development/building_ecal_from_source.rst b/doc/rst/development/building_ecal_from_source.rst index 89db9fc312..5199c5c23a 100644 --- a/doc/rst/development/building_ecal_from_source.rst +++ b/doc/rst/development/building_ecal_from_source.rst @@ -87,7 +87,7 @@ First check out the eCAL repository and all of the submodules: rem Replace with your Qt installation path: set "CMAKE_PREFIX_PATH=C:/Qt/5.15.2/msvc2019_64" - cmake ../.. -A x64 -DCMAKE_INSTALL_PREFIX=_install -DBUILD_SHARED_LIBS=OFF + cmake ../.. -A x64 -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake -DCMAKE_INSTALL_PREFIX=_install -DBUILD_SHARED_LIBS=OFF cmake --build . --parallel --config Release This will create a :file:`_build\\complete\\` directory in your eCAL root folder and build eCAL there. @@ -100,7 +100,7 @@ We support building on currently supported Ubuntu LTS releases. .. seealso:: - The build described here is a very simple (yet complete and fully functional) build that differs from our "official" binaries, e.g. in regards of the library install directory and the :file:`ecal.ini` location-. + The build described here is a very simple (yet complete and fully functional) build that differs from our "official" binaries, e.g. in regards of the library install directory and the :file:`ecal.yaml` location-. If your goal is to replicate the official build, you should apply the CMake Options exactly as we do. You can grab those from our GitHub Action build scripts: @@ -151,7 +151,7 @@ We support building on currently supported Ubuntu LTS releases. mkdir _build cd _build - cmake .. -DCMAKE_BUILD_TYPE=Release -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF -DECAL_THIRDPARTY_BUILD_CURL=OFF -DECAL_THIRDPARTY_BUILD_HDF5=OFF -DECAL_THIRDPARTY_BUILD_QWT=OFF + cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=cmake/submodule_dependencies.cmake -DECAL_THIRDPARTY_BUILD_PROTOBUF=OFF -DECAL_THIRDPARTY_BUILD_CURL=OFF -DECAL_THIRDPARTY_BUILD_HDF5=OFF -DECAL_THIRDPARTY_BUILD_QWT=OFF make -j4 #. Create a debian package and install it: diff --git a/doc/rst/development/ecal_cmake_options.rst b/doc/rst/development/ecal_cmake_options.rst index 4100834a91..cadb5fa213 100644 --- a/doc/rst/development/ecal_cmake_options.rst +++ b/doc/rst/development/ecal_cmake_options.rst @@ -49,8 +49,6 @@ All options can be passed on the command line cmake ``-D