From 10e6efa795a3d9bbdea312740d44479cba3d2fe2 Mon Sep 17 00:00:00 2001 From: Helen Oleynikova Date: Thu, 17 Nov 2022 16:55:40 +0100 Subject: [PATCH] Core library version 0.0.4. --- Jenkinsfile | 182 +- README.md | 28 +- Dockerfile.build => docker/Dockerfile.build | 0 Dockerfile.deps => docker/Dockerfile.deps | 0 docker/Dockerfile.jetson_deps | 20 + Dockerfile.test => docker/Dockerfile.test | 0 docs/Doxyfile | 51 +- docs/conf.py | 37 +- docs/doxy_header.html | 57 + docs/doxygen-awesome.css | 2405 +++++++++++++++++ docs/images/nvblox_logo.png | Bin 0 -> 1722 bytes docs/images/nvblox_logo_128.png | Bin 0 -> 1306 bytes docs/images/nvblox_logo_32.png | Bin 0 -> 991 bytes docs/images/nvblox_logo_64.png | Bin 0 -> 1084 bytes docs/images/system_diagram.png | Bin 0 -> 103439 bytes docs/pages/integrators.md | 18 + docs/pages/map.md | 53 + docs/pages/nvblox_node.rst | 158 -- docs/pages/technical.md | 26 + docs/pages/technical.rst | 25 - docs/redistributable.md | 51 + docs/root.rst | 8 + docs/{pages => rst}/examples/core_example.rst | 0 docs/{pages => rst}/examples/index.rst | 0 docs/{pages => rst}/examples/ros_example.rst | 0 docs/{ => rst}/index.rst | 19 +- docs/{pages => rst}/installation/core.rst | 0 docs/{pages => rst}/installation/index.rst | 0 docs/{pages => rst}/installation/ros.rst | 0 docs/{pages => rst}/integrators.rst | 0 docs/{pages => rst}/map.rst | 2 +- docs/{pages => rst}/mapper.rst | 0 docs/{pages => rst}/rays.rst | 0 nvblox/CMakeLists.txt | 173 +- .../replica/evaluation_utils/voxel_grid.py | 30 +- .../replica/replica_esdf_evaluation.py | 5 +- .../replica/replica_reconstruction.py | 23 +- .../replica/replica_surface_evaluation.py | 5 + nvblox/examples/CMakeLists.txt | 10 + nvblox/examples/src/esdf_query.cu | 1 + nvblox/examples/src/load_map_and_mesh.cpp | 79 + nvblox/executables/CMakeLists.txt | 10 + .../include/nvblox/datasets/3dmatch.h | 1 + .../include/nvblox/datasets/redwood.h | 70 + .../include/nvblox/datasets/replica.h | 2 + nvblox/executables/src/datasets/3dmatch.cpp | 2 - .../executables/src/datasets/image_loader.cpp | 9 +- nvblox/executables/src/datasets/redwood.cpp | 205 ++ nvblox/executables/src/datasets/replica.cpp | 2 - nvblox/executables/src/fuse_redwood.cpp | 61 + nvblox/include/nvblox/core/accessors.h | 16 +- nvblox/include/nvblox/core/blox.h | 6 + nvblox/include/nvblox/core/bounding_boxes.h | 18 +- nvblox/include/nvblox/core/camera.h | 4 + nvblox/include/nvblox/core/color.h | 13 +- .../include/nvblox/core/cuda/atomic_float.cuh | 24 + .../core/cuda/impl/atomic_float_impl.cuh | 32 + .../nvblox/core/cuda/impl/layer_impl.cuh | 70 + nvblox/include/nvblox/core/image.h | 36 +- nvblox/include/nvblox/core/impl/image_impl.h | 2 - .../nvblox/core/impl/interpolation_2d_impl.h | 6 + .../nvblox/core/impl/unified_vector_impl.h | 2 +- nvblox/include/nvblox/core/indexing.h | 4 +- nvblox/include/nvblox/core/interpolation_2d.h | 8 +- nvblox/include/nvblox/core/interpolation_3d.h | 4 +- nvblox/include/nvblox/core/iterator.h | 2 + nvblox/include/nvblox/core/layer.h | 45 +- nvblox/include/nvblox/core/layer_cake.h | 22 +- nvblox/include/nvblox/core/lidar.h | 22 +- nvblox/include/nvblox/core/mapper.h | 65 +- nvblox/include/nvblox/core/pointcloud.h | 91 + nvblox/include/nvblox/core/types.h | 12 +- nvblox/include/nvblox/core/unified_ptr.h | 56 +- nvblox/include/nvblox/core/unified_vector.h | 30 +- nvblox/include/nvblox/core/voxels.h | 22 +- .../cuda/impl/gpu_layer_view_impl.cuh | 5 +- nvblox/include/nvblox/io/csv.h | 1 + .../nvblox/io/impl/pointcloud_io_impl.h | 27 - nvblox/include/nvblox/io/pointcloud_io.h | 8 - nvblox/include/nvblox/mesh/marching_cubes.h | 28 +- nvblox/include/nvblox/mesh/mesh.h | 11 +- nvblox/include/nvblox/mesh/mesh_block.h | 28 +- nvblox/include/nvblox/mesh/mesh_integrator.h | 16 +- nvblox/include/nvblox/nvblox.h | 8 + nvblox/include/nvblox/primitives/primitives.h | 8 +- nvblox/include/nvblox/primitives/scene.h | 12 +- nvblox/include/nvblox/rays/ray_caster.h | 7 +- .../include/nvblox/semantics/image_masker.h | 106 + .../nvblox/semantics/image_projector.h | 58 + .../nvblox/serialization/common_types.h | 6 +- .../serialization/layer_type_register.h | 12 +- .../include/nvblox/serialization/serializer.h | 14 +- .../nvblox/serialization/sqlite_database.h | 11 +- nvblox/include/nvblox/utils/nvtx_ranges.h | 2 + nvblox/src/core/color.cpp | 2 + nvblox/src/core/cuda/layer.cu | 36 + nvblox/src/core/cuda/pointcloud.cu | 71 + nvblox/src/core/mapper.cpp | 52 + .../src/integrators/cuda/esdf_integrator.cu | 23 +- .../cuda/projective_color_integrator.cu | 6 +- .../src/integrators/cuda/view_calculator.cu | 16 +- nvblox/src/integrators/view_calculator.cpp | 3 + nvblox/src/io/csv.cpp | 34 +- nvblox/src/io/pointcloud_io.cpp | 42 + nvblox/src/mesh/mesh_integrator.cu | 3 +- nvblox/src/semantics/cuda/image_masker.cu | 321 +++ nvblox/src/semantics/cuda/image_projector.cu | 124 + nvblox/tests/CMakeLists.txt | 17 + nvblox/tests/include/nvblox/tests/blox.h | 27 +- .../tests/include/nvblox/tests/blox_utils.h | 2 + nvblox/tests/include/nvblox/tests/voxels.h | 24 + nvblox/tests/lib/cuda/blox.cu | 9 +- nvblox/tests/lib/cuda/blox_utils.cu | 23 +- nvblox/tests/lib/cuda/layer.cu | 28 + .../lib/projective_tsdf_integrator_cpu.cpp | 2 + nvblox/tests/test_cake.cpp | 6 +- nvblox/tests/test_color_image.cpp | 19 +- nvblox/tests/test_color_integrator.cpp | 9 +- nvblox/tests/test_frustum.cpp | 1 + nvblox/tests/test_fuser.cpp | 1 + nvblox/tests/test_human_mapper.cpp | 126 + nvblox/tests/test_image_masker.cpp | 249 ++ nvblox/tests/test_image_projector.cpp | 120 + nvblox/tests/test_layer.cpp | 104 +- nvblox/tests/test_pointcloud.cpp | 149 + nvblox/tests/test_sphere_tracing.cpp | 2 + nvblox/tests/test_traits.cpp | 27 +- .../test_tsdf_integrator_cuda_components.cpp | 1 + .../visualize_csv_color_image.py | 30 + .../visualization/visualize_csv_pointcloud.py | 23 + nvblox/thirdparty/stdgpu/stdgpu.cmake | 2 +- 131 files changed, 5872 insertions(+), 670 deletions(-) rename Dockerfile.build => docker/Dockerfile.build (100%) rename Dockerfile.deps => docker/Dockerfile.deps (100%) create mode 100644 docker/Dockerfile.jetson_deps rename Dockerfile.test => docker/Dockerfile.test (100%) create mode 100644 docs/doxy_header.html create mode 100644 docs/doxygen-awesome.css create mode 100644 docs/images/nvblox_logo.png create mode 100644 docs/images/nvblox_logo_128.png create mode 100644 docs/images/nvblox_logo_32.png create mode 100644 docs/images/nvblox_logo_64.png create mode 100644 docs/images/system_diagram.png create mode 100644 docs/pages/integrators.md create mode 100644 docs/pages/map.md delete mode 100644 docs/pages/nvblox_node.rst create mode 100644 docs/pages/technical.md delete mode 100644 docs/pages/technical.rst create mode 100644 docs/redistributable.md create mode 100644 docs/root.rst rename docs/{pages => rst}/examples/core_example.rst (100%) rename docs/{pages => rst}/examples/index.rst (100%) rename docs/{pages => rst}/examples/ros_example.rst (100%) rename docs/{ => rst}/index.rst (74%) rename docs/{pages => rst}/installation/core.rst (100%) rename docs/{pages => rst}/installation/index.rst (100%) rename docs/{pages => rst}/installation/ros.rst (100%) rename docs/{pages => rst}/integrators.rst (100%) rename docs/{pages => rst}/map.rst (98%) rename docs/{pages => rst}/mapper.rst (100%) rename docs/{pages => rst}/rays.rst (100%) create mode 100644 nvblox/examples/src/load_map_and_mesh.cpp create mode 100644 nvblox/executables/include/nvblox/datasets/redwood.h create mode 100644 nvblox/executables/src/datasets/redwood.cpp create mode 100644 nvblox/executables/src/fuse_redwood.cpp create mode 100644 nvblox/include/nvblox/core/cuda/atomic_float.cuh create mode 100644 nvblox/include/nvblox/core/cuda/impl/atomic_float_impl.cuh create mode 100644 nvblox/include/nvblox/core/cuda/impl/layer_impl.cuh create mode 100644 nvblox/include/nvblox/core/pointcloud.h create mode 100644 nvblox/include/nvblox/semantics/image_masker.h create mode 100644 nvblox/include/nvblox/semantics/image_projector.h create mode 100644 nvblox/src/core/cuda/layer.cu create mode 100644 nvblox/src/core/cuda/pointcloud.cu create mode 100644 nvblox/src/io/pointcloud_io.cpp create mode 100644 nvblox/src/semantics/cuda/image_masker.cu create mode 100644 nvblox/src/semantics/cuda/image_projector.cu create mode 100644 nvblox/tests/include/nvblox/tests/voxels.h create mode 100644 nvblox/tests/lib/cuda/layer.cu create mode 100644 nvblox/tests/test_human_mapper.cpp create mode 100644 nvblox/tests/test_image_masker.cpp create mode 100644 nvblox/tests/test_image_projector.cpp create mode 100644 nvblox/tests/test_pointcloud.cpp create mode 100755 nvblox/tests/visualization/visualize_csv_color_image.py create mode 100755 nvblox/tests/visualization/visualize_csv_pointcloud.py diff --git a/Jenkinsfile b/Jenkinsfile index 02b0adb1..b764229b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,66 +1,144 @@ pipeline { - agent { - dockerfile { - label 'isaac-gpu' - reuseNode true - filename 'Dockerfile.deps' - args '-u root --gpus all -v /var/run/docker.sock:/var/run/docker.sock:rw' - } - } + agent none triggers { gitlab(triggerOnMergeRequest: true, branchFilterType: 'All') } stages { - stage('Compile') { - steps { - sh '''mkdir -p nvblox/build''' - sh '''mkdir -p nvblox/install''' - sh '''cd nvblox/build && cmake .. -DCMAKE_INSTALL_PREFIX=../install && make -j8 && make install''' - } - } - stage('Test') { - steps { - sh '''cd nvblox/build/tests && ctest -T test --no-compress-output''' - } - } - stage('Link Into External Project') { - steps { - dir("nvblox_lib_test") { - git credentialsId: 'vault-svc-ssh', url: 'ssh://git@gitlab-master.nvidia.com:12051/nvblox/nvblox_lib_test.git', branch: 'main' + stage("Compile & Test Multiplatform") { + parallel { + stage("x86") { + agent { + dockerfile { + label 'isaac-gpu' + reuseNode true + filename 'docker/Dockerfile.deps' + args '-u root --gpus all -v /var/run/docker.sock:/var/run/docker.sock:rw' + } + } + stages { + stage('Compile x86') { + steps { + sh '''mkdir -p nvblox/build''' + sh '''mkdir -p nvblox/install''' + sh '''cd nvblox/build && cmake .. -DCMAKE_INSTALL_PREFIX=../install && make clean && make -j8 && make install''' + } + } + stage('Test x86') { + steps { + sh '''cd nvblox/build/tests && ctest -T test --no-compress-output''' + } + } + stage('Link Into External Project x86') { + steps { + dir("nvblox_lib_test") { + git credentialsId: 'vault-svc-ssh', url: 'ssh://git@gitlab-master.nvidia.com:12051/nvblox/nvblox_lib_test.git', branch: 'main' + } + sh '''mkdir -p nvblox_lib_test/build''' + sh '''cd nvblox_lib_test/build && cmake .. -DNVBLOX_INSTALL_PATH=${WORKSPACE}/nvblox/install && make''' + sh '''cd nvblox_lib_test/build && ./min_example''' + } + } + stage("Cleanup x86") { + steps { + // Archive the CTest xml output + archiveArtifacts ( + artifacts: 'nvblox/build/tests/Testing/**/*.xml', + fingerprint: true + ) + + // Process the CTest xml output with the xUnit plugin + xunit ( + testTimeMargin: '3000', + thresholdMode: 1, + thresholds: [ + skipped(failureThreshold: '0'), + failed(failureThreshold: '0') + ], + tools: [CTest( + pattern: 'nvblox/build/tests/Testing/**/*.xml', + deleteOutputFiles: true, + failIfNotNew: false, + skipNoTestFiles: true, + stopProcessingIfError: true + )] + ) + + // Clear the source and build dirs before next run + cleanWs() + } + } + } + } + stage("Jetson 5.0.2") { + agent { + dockerfile { + label 'jetson-5.0.2' + reuseNode true + filename 'docker/Dockerfile.jetson_deps' + args '-u root --runtime nvidia --gpus all -v /var/run/docker.sock:/var/run/docker.sock:rw' + } + } + stages { + stage('Compile Jetson') { + steps { + sh '''mkdir -p nvblox/build''' + sh '''mkdir -p nvblox/install''' + sh '''cd nvblox/build && cmake .. -DCMAKE_INSTALL_PREFIX=../install && make clean && make -j8 && make install''' + } + } + stage('Test Jetson') { + steps { + sh '''cd nvblox/build/tests && ctest -T test --no-compress-output''' + } + } + stage('Link Into External Project Jetson') { + steps { + dir("nvblox_lib_test") { + git credentialsId: 'vault-svc-ssh', url: 'ssh://git@gitlab-master.nvidia.com:12051/nvblox/nvblox_lib_test.git', branch: 'main' + } + sh '''mkdir -p nvblox_lib_test/build''' + sh '''cd nvblox_lib_test/build && cmake .. -DNVBLOX_INSTALL_PATH=${WORKSPACE}/nvblox/install && make''' + sh '''cd nvblox_lib_test/build && ./min_example''' + } + } + stage("Cleanup Jetson") { + steps { + archiveArtifacts ( + artifacts: 'nvblox/build/tests/Testing/**/*.xml', + fingerprint: true + ) + + // Process the CTest xml output with the xUnit plugin + xunit ( + testTimeMargin: '3000', + thresholdMode: 1, + thresholds: [ + skipped(failureThreshold: '0'), + failed(failureThreshold: '0') + ], + tools: [CTest( + pattern: 'nvblox/build/tests/Testing/**/*.xml', + deleteOutputFiles: true, + failIfNotNew: false, + skipNoTestFiles: true, + stopProcessingIfError: true + )] + ) + + // Clear the source and build dirs before next run + cleanWs() + } + } + } } - sh '''mkdir -p nvblox_lib_test/build''' - sh '''cd nvblox_lib_test/build && cmake .. -DNVBLOX_INSTALL_PATH=${WORKSPACE}/nvblox/install && make''' - sh '''cd nvblox_lib_test/build && ./min_example''' } } } post { always { - // Archive the CTest xml output - archiveArtifacts ( - artifacts: 'nvblox/build/tests/Testing/**/*.xml', - fingerprint: true - ) - - // Process the CTest xml output with the xUnit plugin - xunit ( - testTimeMargin: '3000', - thresholdMode: 1, - thresholds: [ - skipped(failureThreshold: '0'), - failed(failureThreshold: '0') - ], - tools: [CTest( - pattern: 'nvblox/build/Testing/**/*.xml', - deleteOutputFiles: true, - failIfNotNew: false, - skipNoTestFiles: true, - stopProcessingIfError: true - )] - ) - - // Clear the source and build dirs before next run - cleanWs() + agent { + label 'isaac-gpu' + } } failure { updateGitlabCommitStatus name: 'build', state: 'failed' diff --git a/README.md b/README.md index b2b84c11..49130b3b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ # nvblox Signed Distance Functions (SDFs) on NVIDIA GPUs. +
+ An SDF library which offers * Support for storage of various voxel types * GPU accelerated agorithms such as: * TSDF construction * ESDF construction + * Meshing * ROS2 interface (see [isaac_ros_nvblox](https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_nvblox)) * ~~Python bindings~~ (coming soon) @@ -31,7 +34,7 @@ We depend on: - gtest - glog - gflags (to run experiments) -- CUDA 10.2 - 11.5 (others might work but are untested) +- CUDA 11.0 - 11.6 (others might work but are untested) - Eigen (no need to explicitly install, a recent version is built into the library) - SQLite 3 (for serialization) Please run @@ -69,11 +72,13 @@ you should see a mesh of a room: # Docker -We have several dockerfiles which layer on top of one another for the following purposes: +We have several dockerfiles (in the `docker` subfolder) which layer on top of one another for the following purposes: * **Docker.deps** * * This installs our dependencies. * * This is used in our CI, where the later steps (building and testing) are taken care of by Jenkins (and not docker). +* **Docker.jetson_deps** +* * Same as above, just on the Jetson (Jetpack 5 and above). * **Docker.build** * * Layers on top of Docker.deps. * * This builds our package. @@ -101,13 +106,13 @@ Restart docker ``` sudo systemctl restart docker ``` -Now Let's build Dockerfile.deps docker image. This image install contains our dependacies. +Now Let's build Dockerfile.deps docker image. This image install contains our dependencies. (In case you are running this on the Jetson, simply substitute docker/`Dockerfile.jetson_deps` below and the rest of the instructions remain the same. ``` -docker build -t nvblox_deps -f Dockerfile.deps . +docker build -t nvblox_deps -f docker/Dockerfile.deps . ``` Now let's build the Dockerfile.build. This image layers on the last, and actually builds the nvblox library. ``` -docker build -t nvblox -f Dockerfile.build . +docker build -t nvblox -f docker/Dockerfile.build . ``` Now let's run the 3DMatch example inside the docker. Note there's some additional complexity in the `docker run` command such that we can forward X11 to the host (we're going to be view a reconstruction in a GUI). Run the container using: ``` @@ -120,7 +125,7 @@ apt-get update apt-get install unzip wget http://vision.princeton.edu/projects/2016/3DMatch/downloads/rgbd-datasets/sun3d-mit_76_studyroom-76-1studyroom2.zip -P ~/datasets/3dmatch unzip ~/datasets/3dmatch/sun3d-mit_76_studyroom-76-1studyroom2.zip -d ~/datasets/3dmatch -cd nvblox/nvblox/build/experiments/ +cd nvblox/nvblox/build/executables/ ./fuse_3dmatch ~/datasets/3dmatch/sun3d-mit_76_studyroom-76-1studyroom2/ --esdf_frame_subsampling 3000 --mesh_output_path mesh.ply ``` Now let's visualize. From the same experiments folder run: @@ -131,7 +136,7 @@ python3 ../../visualization/visualize_mesh.py mesh.ply ``` # Additional instructions for Jetson Xavier -These instructions are for a native build on the Jetson Xavier. A Docker based build is coming soon. +These instructions are for a native build on the Jetson Xavier. You can see the instructions above for running in docker. The instructions for the native build above work, with one exception: @@ -156,5 +161,14 @@ sudo apt-get install cmake export OPENBLAS_CORETYPE=ARMV8 ``` +# Building for multiple GPU architectures +By default, the library builds ONLY for the compute capability (CC) of the machine it's being built on. To build binaries that can be used across multiple machines (i.e., pre-built binaries for CI, for example), you can use the `BUILD_FOR_ALL_ARCHS` flag and set it to true. Example: +``` +cmake .. -DBUILD_FOR_ALL_ARCHS=True -DCMAKE_INSTALL_PREFIX=../install/ && make -j8 && make install +``` + +# Building redistributable binaries, with static dependencies +If you want to include nvblox in another CMake project, simply `find_package(nvblox)` should bring in the correct libraries and headers. However, if you want to include it in a different build system such as Bazel, you can see the instructions here: [docs/redistibutable.md]. + # License This code is under an [open-source license](LICENSE) (Apache 2.0). :) diff --git a/Dockerfile.build b/docker/Dockerfile.build similarity index 100% rename from Dockerfile.build rename to docker/Dockerfile.build diff --git a/Dockerfile.deps b/docker/Dockerfile.deps similarity index 100% rename from Dockerfile.deps rename to docker/Dockerfile.deps diff --git a/docker/Dockerfile.jetson_deps b/docker/Dockerfile.jetson_deps new file mode 100644 index 00000000..d218b2d4 --- /dev/null +++ b/docker/Dockerfile.jetson_deps @@ -0,0 +1,20 @@ +FROM nvcr.io/nvidia/l4t-jetpack:r35.1.0 + +# TZData goes first. +RUN apt-get update +ENV TZ Europe/Berlin +ENV DEBIAN_FRONTEND noninteractive +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +RUN apt-get install -y tzdata + +# Install basics. +RUN apt-get update +RUN apt-get install -y ssh git jq gnupg apt-utils software-properties-common build-essential cmake + +# Install dependencies. +RUN apt-get install -y libgoogle-glog-dev libgtest-dev curl libsqlite3-dev + +# Build gtest because gtest doesn't do this for you for some reason. +RUN cd /usr/src/googletest && cmake . && cmake --build . --target install + +ENV DEBIAN_FRONTEND teletype diff --git a/Dockerfile.test b/docker/Dockerfile.test similarity index 100% rename from Dockerfile.test rename to docker/Dockerfile.test diff --git a/docs/Doxyfile b/docs/Doxyfile index 5bf8689b..48c71425 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "project" +PROJECT_NAME = "nvblox" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version @@ -44,14 +44,14 @@ PROJECT_NUMBER = # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = "Building signed distance fields for robots from sensor data on Nvidia GPUs." # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = +PROJECT_LOGO = ./images/nvblox_logo_64.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -150,7 +150,7 @@ INLINE_INHERITED_MEMB = NO # shortest path that makes the file name unique will be used # The default value is: YES. -FULL_PATH_NAMES = YES +FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand @@ -461,7 +461,7 @@ EXTRACT_STATIC = YES # for Java sources. # The default value is: YES. -EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_CLASSES = NO # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are @@ -680,7 +680,7 @@ SHOW_FILES = YES # Folder Tree View (if specified). # The default value is: YES. -SHOW_NAMESPACES = NO +SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from @@ -790,7 +790,10 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../nvblox/include +INPUT = ../README.md \ + pages/ \ + images/ \ + ../nvblox/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -819,7 +822,8 @@ FILE_PATTERNS = *.h \ *.hh \ *.hxx \ *.hpp \ - *.h++ + *.h++ \ + *.md # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -834,7 +838,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -850,7 +854,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = *_impl.h +EXCLUDE_PATTERNS = *_impl.h */traits.h # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -887,7 +891,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = ./images/ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -943,7 +947,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = README.md #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1083,7 +1087,7 @@ IGNORE_PREFIX = # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. -GENERATE_HTML = NO +GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -1118,7 +1122,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = doxy_header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1153,7 +1157,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = doxygen-awesome.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1163,7 +1167,7 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = images/nvblox_logo_32.png # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to @@ -1204,13 +1208,24 @@ HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1439,7 +1454,7 @@ DISABLE_INDEX = NO # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = NO +GENERATE_TREEVIEW = YES # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. diff --git a/docs/conf.py b/docs/conf.py index c893ba47..e8a29822 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,5 @@ import os +import subprocess name = 'nvblox' @@ -9,37 +10,41 @@ html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -# html_logo = "logo.gif" +subprocess.call('doxygen', shell=True) + +html_logo = "images/nvblox_logo_128.png" source_parsers = { '.md': 'recommonmark.parser.CommonMarkParser', } extensions = [ - 'sphinx.ext.autosectionlabel', 'recommonmark' #'breathe' 'exhale' + 'sphinx.ext.autosectionlabel', 'myst_parser', #'breathe', 'exhale', ] project = name -master_doc = 'index' +master_doc = 'root' # html_theme_options = {'logo_only': True} +html_extra_path = ['doxyoutput/html'] + -# Setup the breathe extension +# # Setup the breathe extension # breathe_projects = {"project": "./doxyoutput/xml"} # breathe_default_project = "project" -# Setup the exhale extension -exhale_args = { - "verboseBuild": False, - "containmentFolder": "./api", - "rootFileName": "library_root.rst", - "rootFileTitle": "Library API", - "doxygenStripFromPath": "..", - "createTreeView": True, - # "exhaleExecutesDoxygen": False, # SWITCH TO TRUE - # "exhaleUseDoxyfile": False, # SWITCH TO TRUE - # "pageLevelConfigMeta": ":github_url: https://github.com/ethz-asl/" + name -} +# # Setup the exhale extension +# exhale_args = { +# "verboseBuild": False, +# "containmentFolder": "./api", +# "rootFileName": "library_root.rst", +# "rootFileTitle": "Library API", +# "doxygenStripFromPath": "..", +# "createTreeView": True, +# "exhaleExecutesDoxygen": True, # SWITCH TO TRUE +# "exhaleUseDoxyfile": True, # SWITCH TO TRUE +# "pageLevelConfigMeta": ":github_url: https://github.com/nvidia-isaac/" + name +# } source_suffix = ['.rst', '.md'] diff --git a/docs/doxy_header.html b/docs/doxy_header.html new file mode 100644 index 00000000..37e6d3a2 --- /dev/null +++ b/docs/doxy_header.html @@ -0,0 +1,57 @@ + + + + + + + + +$projectname: $title +$title + + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/docs/doxygen-awesome.css b/docs/doxygen-awesome.css new file mode 100644 index 00000000..121eb0fd --- /dev/null +++ b/docs/doxygen-awesome.css @@ -0,0 +1,2405 @@ +/** + +Doxygen Awesome +https://github.com/jothepro/doxygen-awesome-css + +MIT License + +Copyright (c) 2021 - 2022 jothepro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +html { + /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ + --primary-color: #1779c4; + --primary-dark-color: #335c80; + --primary-light-color: #70b1e9; + + /* page base colors */ + --page-background-color: #ffffff; + --page-foreground-color: #2f4153; + --page-secondary-foreground-color: #6f7e8e; + + /* color for all separators on the website: hr, borders, ... */ + --separator-color: #dedede; + + /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ + --border-radius-large: 8px; + --border-radius-small: 4px; + --border-radius-medium: 6px; + + /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ + --spacing-small: 5px; + --spacing-medium: 10px; + --spacing-large: 16px; + + /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); + + --odd-color: rgba(0,0,0,.028); + + /* font-families. will affect all text on the website + * font-family: the normal font for text, headlines, menus + * font-family-monospace: used for preformatted text in memtitle, code, fragments + */ + --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; + --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + + /* font sizes */ + --page-font-size: 15.6px; + --navigation-font-size: 14.4px; + --toc-font-size: 13.4px; + --code-font-size: 14px; /* affects code, fragment */ + --title-font-size: 22px; + + /* content text properties. These only affect the page content, not the navigation or any other ui elements */ + --content-line-height: 27px; + /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ + --content-maxwidth: 1050px; + --table-line-height: 24px; + --toc-sticky-top: var(--spacing-medium); + --toc-width: 200px; + --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); + + /* colors for various content boxes: @warning, @note, @deprecated @bug */ + --warning-color: #f8d1cc; + --warning-color-dark: #b61825; + --warning-color-darker: #75070f; + --note-color: #faf3d8; + --note-color-dark: #f3a600; + --note-color-darker: #5f4204; + --todo-color: #e4f3ff; + --todo-color-dark: #1879C4; + --todo-color-darker: #274a5c; + --deprecated-color: #ecf0f3; + --deprecated-color-dark: #5b6269; + --deprecated-color-darker: #43454a; + --bug-color: #e4dafd; + --bug-color-dark: #5b2bdd; + --bug-color-darker: #2a0d72; + --invariant-color: #d8f1e3; + --invariant-color-dark: #44b86f; + --invariant-color-darker: #265532; + + /* blockquote colors */ + --blockquote-background: #f8f9fa; + --blockquote-foreground: #636568; + + /* table colors */ + --tablehead-background: #f1f1f1; + --tablehead-foreground: var(--page-foreground-color); + + /* menu-display: block | none + * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. + * `GENERATE_TREEVIEW` MUST be enabled! + */ + --menu-display: block; + + --menu-focus-foreground: var(--page-background-color); + --menu-focus-background: var(--primary-color); + --menu-selected-background: rgba(0,0,0,.05); + + + --header-background: var(--page-background-color); + --header-foreground: var(--page-foreground-color); + + /* searchbar colors */ + --searchbar-background: var(--side-nav-background); + --searchbar-foreground: var(--page-foreground-color); + + /* searchbar size + * (`searchbar-width` is only applied on screens >= 768px. + * on smaller screens the searchbar will always fill the entire screen width) */ + --searchbar-height: 33px; + --searchbar-width: 210px; + --searchbar-border-radius: var(--searchbar-height); + + /* code block colors */ + --code-background: #f5f5f5; + --code-foreground: var(--page-foreground-color); + + /* fragment colors */ + --fragment-background: #F8F9FA; + --fragment-foreground: #37474F; + --fragment-keyword: #bb6bb2; + --fragment-keywordtype: #8258b3; + --fragment-keywordflow: #d67c3b; + --fragment-token: #438a59; + --fragment-comment: #969696; + --fragment-link: #5383d6; + --fragment-preprocessor: #46aaa5; + --fragment-linenumber-color: #797979; + --fragment-linenumber-background: #f4f4f5; + --fragment-linenumber-border: #e3e5e7; + --fragment-lineheight: 20px; + + /* sidebar navigation (treeview) colors */ + --side-nav-background: #fbfbfb; + --side-nav-foreground: var(--page-foreground-color); + --side-nav-arrow-opacity: 0; + --side-nav-arrow-hover-opacity: 0.9; + + --toc-background: var(--side-nav-background); + --toc-foreground: var(--side-nav-foreground); + + /* height of an item in any tree / collapsable table */ + --tree-item-height: 30px; + + --memname-font-size: var(--code-font-size); + --memtitle-font-size: 18px; + + --webkit-scrollbar-size: 7px; + --webkit-scrollbar-padding: 4px; + --webkit-scrollbar-color: var(--separator-color); +} + +@media screen and (max-width: 767px) { + html { + --page-font-size: 16px; + --navigation-font-size: 16px; + --toc-font-size: 15px; + --code-font-size: 15px; /* affects code, fragment */ + --title-font-size: 22px; + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; + } +} + +/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ +html.dark-mode { + color-scheme: dark; + + --primary-color: #1982d2; + --primary-dark-color: #86a9c4; + --primary-light-color: #4779ac; + + --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); + + --odd-color: rgba(100,100,100,.06); + + --menu-selected-background: rgba(0,0,0,.4); + + --page-background-color: #1C1D1F; + --page-foreground-color: #d2dbde; + --page-secondary-foreground-color: #859399; + --separator-color: #38393b; + --side-nav-background: #252628; + + --code-background: #2a2c2f; + + --tablehead-background: #2a2c2f; + + --blockquote-background: #222325; + --blockquote-foreground: #7e8c92; + + --warning-color: #2e1917; + --warning-color-dark: #ad2617; + --warning-color-darker: #f5b1aa; + --note-color: #3b2e04; + --note-color-dark: #f1b602; + --note-color-darker: #ceb670; + --todo-color: #163750; + --todo-color-dark: #1982D2; + --todo-color-darker: #dcf0fa; + --deprecated-color: #2e323b; + --deprecated-color-dark: #738396; + --deprecated-color-darker: #abb0bd; + --bug-color: #2a2536; + --bug-color-dark: #7661b3; + --bug-color-darker: #ae9ed6; + --invariant-color: #303a35; + --invariant-color-dark: #76ce96; + --invariant-color-darker: #cceed5; + + --fragment-background: #282c34; + --fragment-foreground: #dbe4eb; + --fragment-keyword: #cc99cd; + --fragment-keywordtype: #ab99cd; + --fragment-keywordflow: #e08000; + --fragment-token: #7ec699; + --fragment-comment: #999999; + --fragment-link: #98c0e3; + --fragment-preprocessor: #65cabe; + --fragment-linenumber-color: #cccccc; + --fragment-linenumber-background: #35393c; + --fragment-linenumber-border: #1f1f1f; +} + +body { + color: var(--page-foreground-color); + background-color: var(--page-background-color); + font-size: var(--page-font-size); +} + +body, table, div, p, dl, #nav-tree .label, .title, +.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, +.SelectItem, #MSearchField, .navpath li.navelem a, +.navpath li.navelem a:hover, p.reference, p.definition { + font-family: var(--font-family); +} + +h1, h2, h3, h4, h5 { + margin-top: .9em; + font-weight: 600; + line-height: initial; +} + +p, div, table, dl, p.reference, p.definition { + font-size: var(--page-font-size); +} + +p.reference, p.definition { + color: var(--page-secondary-foreground-color); +} + +a:link, a:visited, a:hover, a:focus, a:active { + color: var(--primary-color) !important; + font-weight: 500; +} + +a.anchor { + scroll-margin-top: var(--spacing-large); + display: block; +} + +/* +Title and top navigation +*/ + +#top { + background: var(--header-background); + border-bottom: 1px solid var(--separator-color); +} + +@media screen and (min-width: 768px) { + #top { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + } +} + +#main-nav { + flex-grow: 5; + padding: var(--spacing-small) var(--spacing-medium); +} + +#titlearea { + width: auto; + padding: var(--spacing-medium) var(--spacing-large); + background: none; + color: var(--header-foreground); + border-bottom: none; +} + +@media screen and (max-width: 767px) { + #titlearea { + padding-bottom: var(--spacing-small); + } +} + +#titlearea table tbody tr { + height: auto !important; +} + +#projectname { + font-size: var(--title-font-size); + font-weight: 600; +} + +#projectnumber { + font-family: inherit; + font-size: 60%; +} + +#projectbrief { + font-family: inherit; + font-size: 80%; +} + +#projectlogo { + vertical-align: middle; +} + +#projectlogo img { + max-height: 64px; + margin-right: var(--spacing-small); +} + +.sm-dox, .tabs, .tabs2, .tabs3 { + background: none; + padding: 0; +} + +.tabs, .tabs2, .tabs3 { + border-bottom: 1px solid var(--separator-color); + margin-bottom: -1px; +} + +.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { + background: var(--page-secondary-foreground-color); +} + +@media screen and (max-width: 767px) { + .sm-dox a span.sub-arrow { + background: var(--code-background); + } + + #main-menu a.has-submenu span.sub-arrow { + color: var(--page-secondary-foreground-color); + border-radius: var(--border-radius-medium); + } + + #main-menu a.has-submenu:hover span.sub-arrow { + color: var(--page-foreground-color); + } +} + +@media screen and (min-width: 768px) { + .sm-dox li, .tablist li { + display: var(--menu-display); + } + + .sm-dox a span.sub-arrow { + border-color: var(--header-foreground) transparent transparent transparent; + } + + .sm-dox a:hover span.sub-arrow { + border-color: var(--menu-focus-foreground) transparent transparent transparent; + } + + .sm-dox ul a span.sub-arrow { + border-color: transparent transparent transparent var(--page-foreground-color); + } + + .sm-dox ul a:hover span.sub-arrow { + border-color: transparent transparent transparent var(--menu-focus-foreground); + } +} + +.sm-dox ul { + background: var(--page-background-color); + box-shadow: var(--box-shadow); + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium) !important; + padding: var(--spacing-small); + animation: ease-out 150ms slideInMenu; +} + +@keyframes slideInMenu { + from { + opacity: 0; + transform: translate(0px, -2px); + } + + to { + opacity: 1; + transform: translate(0px, 0px); + } +} + +.sm-dox ul a { + color: var(--page-foreground-color) !important; + background: var(--page-background-color); + font-size: var(--navigation-font-size); +} + +.sm-dox>li>ul:after { + border-bottom-color: var(--page-background-color) !important; +} + +.sm-dox>li>ul:before { + border-bottom-color: var(--separator-color) !important; +} + +.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { + font-size: var(--navigation-font-size) !important; + color: var(--menu-focus-foreground) !important; + text-shadow: none; + background-color: var(--menu-focus-background); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { + text-shadow: none; + background: transparent; + background-image: none !important; + color: var(--header-foreground) !important; + font-weight: normal; + font-size: var(--navigation-font-size); + border-radius: var(--border-radius-small) !important; +} + +.sm-dox a:focus { + outline: auto; +} + +.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { + text-shadow: none; + font-weight: normal; + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; + border-radius: var(--border-radius-small) !important; + font-size: var(--navigation-font-size); +} + +.tablist li.current { + border-radius: var(--border-radius-small); + background: var(--menu-selected-background); +} + +.tablist li { + margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); +} + +.tablist a { + padding: 0 var(--spacing-large); +} + + +/* +Search box +*/ + +#MSearchBox { + height: var(--searchbar-height); + background: var(--searchbar-background); + border-radius: var(--searchbar-border-radius); + border: 1px solid var(--separator-color); + overflow: hidden; + width: var(--searchbar-width); + position: relative; + box-shadow: none; + display: block; + margin-top: 0; +} + +/* until Doxygen 1.9.4 */ +.left img#MSearchSelect { + left: 0; + user-select: none; + padding-left: 8px; +} + +/* Doxygen 1.9.5 */ +.left span#MSearchSelect { + left: 0; + user-select: none; + margin-left: 8px; + padding: 0; +} + +.left #MSearchSelect[src$=".png"] { + padding-left: 0 +} + +.SelectionMark { + user-select: none; +} + +.tabs .left #MSearchSelect { + padding-left: 0; +} + +.tabs #MSearchBox { + position: absolute; + right: var(--spacing-medium); +} + +@media screen and (max-width: 767px) { + .tabs #MSearchBox { + position: relative; + right: 0; + margin-left: var(--spacing-medium); + margin-top: 0; + } +} + +#MSearchSelectWindow, #MSearchResultsWindow { + z-index: 9999; +} + +#MSearchBox.MSearchBoxActive { + border-color: var(--primary-color); + box-shadow: inset 0 0 0 1px var(--primary-color); +} + +#main-menu > li:last-child { + margin-right: 0; +} + +@media screen and (max-width: 767px) { + #main-menu > li:last-child { + height: 50px; + } +} + +#MSearchField { + font-size: var(--navigation-font-size); + height: calc(var(--searchbar-height) - 2px); + background: transparent; + width: calc(var(--searchbar-width) - 64px); +} + +.MSearchBoxActive #MSearchField { + color: var(--searchbar-foreground); +} + +#MSearchSelect { + top: calc(calc(var(--searchbar-height) / 2) - 11px); +} + +#MSearchBox span.left, #MSearchBox span.right { + background: none; + background-image: none; +} + +#MSearchBox span.right { + padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); + position: absolute; + right: var(--spacing-small); +} + +.tabs #MSearchBox span.right { + top: calc(calc(var(--searchbar-height) / 2) - 12px); +} + +@keyframes slideInSearchResults { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } +} + +#MSearchResultsWindow { + left: auto !important; + right: var(--spacing-medium); + border-radius: var(--border-radius-large); + border: 1px solid var(--separator-color); + transform: translate(0, 20px); + box-shadow: var(--box-shadow); + animation: ease-out 280ms slideInSearchResults; + background: var(--page-background-color); +} + +iframe#MSearchResults { + margin: 4px; +} + +iframe { + color-scheme: normal; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) iframe#MSearchResults { + filter: invert() hue-rotate(180deg); + } +} + +html.dark-mode iframe#MSearchResults { + filter: invert() hue-rotate(180deg); +} + +#MSearchResults .SRPage { + background-color: transparent; +} + +#MSearchResults .SRPage .SREntry { + font-size: 10pt; + padding: var(--spacing-small) var(--spacing-medium); +} + +#MSearchSelectWindow { + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + box-shadow: var(--box-shadow); + background: var(--page-background-color); + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); +} + +#MSearchSelectWindow a.SelectItem { + font-size: var(--navigation-font-size); + line-height: var(--content-line-height); + margin: 0 var(--spacing-small); + border-radius: var(--border-radius-small); + color: var(--page-foreground-color) !important; + font-weight: normal; +} + +#MSearchSelectWindow a.SelectItem:hover { + background: var(--menu-focus-background); + color: var(--menu-focus-foreground) !important; +} + +@media screen and (max-width: 767px) { + #MSearchBox { + margin-top: var(--spacing-medium); + margin-bottom: var(--spacing-medium); + width: calc(100vw - 30px); + } + + #main-menu > li:last-child { + float: none !important; + } + + #MSearchField { + width: calc(100vw - 110px); + } + + @keyframes slideInSearchResultsMobile { + from { + opacity: 0; + transform: translate(0, 15px); + } + + to { + opacity: 1; + transform: translate(0, 20px); + } + } + + #MSearchResultsWindow { + left: var(--spacing-medium) !important; + right: var(--spacing-medium); + overflow: auto; + transform: translate(0, 20px); + animation: ease-out 280ms slideInSearchResultsMobile; + width: auto !important; + } + + /* + * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 + */ + label.main-menu-btn ~ #searchBoxPos1 { + top: 3px !important; + right: 6px !important; + left: 45px; + display: flex; + } + + label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { + margin-top: 0; + margin-bottom: 0; + flex-grow: 2; + float: left; + } +} + +/* +Tree view +*/ + +#side-nav { + padding: 0 !important; + background: var(--side-nav-background); +} + +@media screen and (max-width: 767px) { + #side-nav { + display: none; + } + + #doc-content { + margin-left: 0 !important; + } +} + +#nav-tree { + background: transparent; +} + +#nav-tree .label { + font-size: var(--navigation-font-size); +} + +#nav-tree .item { + height: var(--tree-item-height); + line-height: var(--tree-item-height); +} + +#nav-sync { + bottom: 12px; + right: 12px; + top: auto !important; + user-select: none; +} + +#nav-tree .selected { + text-shadow: none; + background-image: none; + background-color: transparent; + position: relative; +} + +#nav-tree .selected::after { + content: ""; + position: absolute; + top: 1px; + bottom: 1px; + left: 0; + width: 4px; + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + background: var(--primary-color); +} + + +#nav-tree a { + color: var(--side-nav-foreground) !important; + font-weight: normal; +} + +#nav-tree a:focus { + outline-style: auto; +} + +#nav-tree .arrow { + opacity: var(--side-nav-arrow-opacity); +} + +.arrow { + color: inherit; + cursor: pointer; + font-size: 45%; + vertical-align: middle; + margin-right: 2px; + font-family: serif; + height: auto; + text-align: right; +} + +#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { + opacity: var(--side-nav-arrow-hover-opacity); +} + +#nav-tree .selected a { + color: var(--primary-color) !important; + font-weight: bolder; + font-weight: 600; +} + +.ui-resizable-e { + background: var(--separator-color); + width: 1px; +} + +/* +Contents +*/ + +div.header { + border-bottom: 1px solid var(--separator-color); + background-color: var(--page-background-color); + background-image: none; +} + +@media screen and (min-width: 1000px) { + #doc-content > div > div.contents, + .PageDoc > div.contents { + display: flex; + flex-direction: row-reverse; + flex-wrap: nowrap; + align-items: flex-start; + } + + div.contents .textblock { + min-width: 200px; + flex-grow: 1; + } +} + +div.contents, div.header .title, div.header .summary { + max-width: var(--content-maxwidth); +} + +div.contents, div.header .title { + line-height: initial; + margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; +} + +div.header .summary { + margin: var(--spacing-medium) auto 0 auto; +} + +div.headertitle { + padding: 0; +} + +div.header .title { + font-weight: 600; + font-size: 225%; + padding: var(--spacing-medium) var(--spacing-large); + word-break: break-word; +} + +div.header .summary { + width: auto; + display: block; + float: none; + padding: 0 var(--spacing-large); +} + +td.memSeparator { + border-color: var(--separator-color); +} + +span.mlabel { + background: var(--primary-color); + border: none; + padding: 4px 9px; + border-radius: 12px; + margin-right: var(--spacing-medium); +} + +span.mlabel:last-of-type { + margin-right: 2px; +} + +div.contents { + padding: 0 var(--spacing-large); +} + +div.contents p, div.contents li { + line-height: var(--content-line-height); +} + +div.contents div.dyncontent { + margin: var(--spacing-medium) 0; +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) div.contents div.dyncontent img, + html:not(.light-mode) div.contents center img, + html:not(.light-mode) div.contents > table img, + html:not(.light-mode) div.contents div.dyncontent iframe, + html:not(.light-mode) div.contents center iframe, + html:not(.light-mode) div.contents table iframe { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode div.contents div.dyncontent img, +html.dark-mode div.contents center img, +html.dark-mode div.contents > table img, +html.dark-mode div.contents div.dyncontent iframe, +html.dark-mode div.contents center iframe, +html.dark-mode div.contents table iframe { + filter: hue-rotate(180deg) invert(); +} + +h2.groupheader { + border-bottom: 0px; + color: var(--page-foreground-color); + box-shadow: + 100px 0 var(--page-background-color), + -100px 0 var(--page-background-color), + 100px 0.75px var(--separator-color), + -100px 0.75px var(--separator-color), + 500px 0 var(--page-background-color), + -500px 0 var(--page-background-color), + 500px 0.75px var(--separator-color), + -500px 0.75px var(--separator-color), + 900px 0 var(--page-background-color), + -900px 0 var(--page-background-color), + 900px 0.75px var(--separator-color), + -900px 0.75px var(--separator-color), + 1400px 0 var(--page-background-color), + -1400px 0 var(--page-background-color), + 1400px 0.75px var(--separator-color), + -1400px 0.75px var(--separator-color), + 1900px 0 var(--page-background-color), + -1900px 0 var(--page-background-color), + 1900px 0.75px var(--separator-color), + -1900px 0.75px var(--separator-color); +} + +blockquote { + margin: 0 var(--spacing-medium) 0 var(--spacing-medium); + padding: var(--spacing-small) var(--spacing-large); + background: var(--blockquote-background); + color: var(--blockquote-foreground); + border-left: 0; + overflow: visible; + border-radius: var(--border-radius-medium); + overflow: visible; + position: relative; +} + +blockquote::before, blockquote::after { + font-weight: bold; + font-family: serif; + font-size: 360%; + opacity: .15; + position: absolute; +} + +blockquote::before { + content: "“"; + left: -10px; + top: 4px; +} + +blockquote::after { + content: "”"; + right: -8px; + bottom: -25px; +} + +blockquote p { + margin: var(--spacing-small) 0 var(--spacing-medium) 0; +} +.paramname { + font-weight: 600; + color: var(--primary-dark-color); +} + +.paramname > code { + border: 0; +} + +table.params .paramname { + font-weight: 600; + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + padding-right: var(--spacing-small); + line-height: var(--table-line-height); +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px var(--primary-light-color); +} + +.alphachar a { + color: var(--page-foreground-color); +} + +/* +Table of Contents +*/ + +div.contents .toc { + max-height: var(--toc-max-height); + min-width: var(--toc-width); + border: 0; + border-left: 1px solid var(--separator-color); + border-radius: 0; + background-color: transparent; + box-shadow: none; + position: sticky; + top: var(--toc-sticky-top); + padding: 0 var(--spacing-large); + margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); +} + +div.toc h3 { + color: var(--toc-foreground); + font-size: var(--navigation-font-size); + margin: var(--spacing-large) 0 var(--spacing-medium) 0; +} + +div.toc li { + padding: 0; + background: none; + line-height: var(--toc-font-size); + margin: var(--toc-font-size) 0 0 0; +} + +div.toc li::before { + display: none; +} + +div.toc ul { + margin-top: 0 +} + +div.toc li a { + font-size: var(--toc-font-size); + color: var(--page-foreground-color) !important; + text-decoration: none; +} + +div.toc li a:hover, div.toc li a.active { + color: var(--primary-color) !important; +} + +div.toc li a.aboveActive { + color: var(--page-secondary-foreground-color) !important; +} + + +@media screen and (max-width: 999px) { + div.contents .toc { + max-height: 45vh; + float: none; + width: auto; + margin: 0 0 var(--spacing-medium) 0; + position: relative; + top: 0; + position: relative; + border: 1px solid var(--separator-color); + border-radius: var(--border-radius-medium); + background-color: var(--toc-background); + box-shadow: var(--box-shadow); + } + + div.contents .toc.interactive { + max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); + overflow: hidden; + } + + div.contents .toc > h3 { + -webkit-tap-highlight-color: transparent; + cursor: pointer; + position: sticky; + top: 0; + background-color: var(--toc-background); + margin: 0; + padding: var(--spacing-large) 0; + display: block; + } + + div.contents .toc.interactive > h3::before { + content: ""; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + display: inline-block; + margin-right: var(--spacing-small); + margin-bottom: calc(var(--navigation-font-size) / 4); + transform: rotate(-90deg); + transition: transform 0.25s ease-out; + } + + div.contents .toc.interactive.open > h3::before { + transform: rotate(0deg); + } + + div.contents .toc.interactive.open { + max-height: 45vh; + overflow: auto; + transition: max-height 0.2s ease-in-out; + } + + div.contents .toc a, div.contents .toc a.active { + color: var(--primary-color) !important; + } + + div.contents .toc a:hover { + text-decoration: underline; + } +} + +/* +Code & Fragments +*/ + +code, div.fragment, pre.fragment { + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + overflow: hidden; +} + +code { + display: inline; + background: var(--code-background); + color: var(--code-foreground); + padding: 2px 6px; +} + +div.fragment, pre.fragment { + margin: var(--spacing-medium) 0; + padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); + background: var(--fragment-background); + color: var(--fragment-foreground); + overflow-x: auto; +} + +@media screen and (max-width: 767px) { + div.fragment, pre.fragment { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: 0; + } + + .contents > div.fragment, + .textblock > div.fragment, + .textblock > pre.fragment, + .contents > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, + .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + border-radius: 0; + border-left: 0; + } + + .textblock li > .fragment, + .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-large)); + } + + .memdoc li > .fragment, + .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + } + + .textblock ul, .memdoc ul { + overflow: initial; + } + + .memdoc > div.fragment, + .memdoc > pre.fragment, + dl dd > div.fragment, + dl dd pre.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, + .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, + dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, + dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { + margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); + border-radius: 0; + border-left: 0; + } +} + +code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size) !important; +} + +div.line:after { + margin-right: var(--spacing-medium); +} + +div.fragment .line, pre.fragment { + white-space: pre; + word-wrap: initial; + line-height: var(--fragment-lineheight); +} + +div.fragment span.keyword { + color: var(--fragment-keyword); +} + +div.fragment span.keywordtype { + color: var(--fragment-keywordtype); +} + +div.fragment span.keywordflow { + color: var(--fragment-keywordflow); +} + +div.fragment span.stringliteral { + color: var(--fragment-token) +} + +div.fragment span.comment { + color: var(--fragment-comment); +} + +div.fragment a.code { + color: var(--fragment-link) !important; +} + +div.fragment span.preprocessor { + color: var(--fragment-preprocessor); +} + +div.fragment span.lineno { + display: inline-block; + width: 27px; + border-right: none; + background: var(--fragment-linenumber-background); + color: var(--fragment-linenumber-color); +} + +div.fragment span.lineno a { + background: none; + color: var(--fragment-link) !important; +} + +div.fragment .line:first-child .lineno { + box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); +} + +div.line { + border-radius: var(--border-radius-small); +} + +div.line.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +/* +dl warning, attention, note, deprecated, bug, ... +*/ + +dl.bug dt a, dl.deprecated dt a, dl.todo dt a { + font-weight: bold !important; +} + +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { + padding: var(--spacing-medium); + margin: var(--spacing-medium) 0; + color: var(--page-background-color); + overflow: hidden; + margin-left: 0; + border-radius: var(--border-radius-small); +} + +dl.section dd { + margin-bottom: 2px; +} + +dl.warning, dl.attention { + background: var(--warning-color); + border-left: 8px solid var(--warning-color-dark); + color: var(--warning-color-darker); +} + +dl.warning dt, dl.attention dt { + color: var(--warning-color-dark); +} + +dl.note, dl.remark { + background: var(--note-color); + border-left: 8px solid var(--note-color-dark); + color: var(--note-color-darker); +} + +dl.note dt, dl.remark dt { + color: var(--note-color-dark); +} + +dl.todo { + background: var(--todo-color); + border-left: 8px solid var(--todo-color-dark); + color: var(--todo-color-darker); +} + +dl.todo dt { + color: var(--todo-color-dark); +} + +dl.bug dt a { + color: var(--todo-color-dark) !important; +} + +dl.bug { + background: var(--bug-color); + border-left: 8px solid var(--bug-color-dark); + color: var(--bug-color-darker); +} + +dl.bug dt a { + color: var(--bug-color-dark) !important; +} + +dl.deprecated { + background: var(--deprecated-color); + border-left: 8px solid var(--deprecated-color-dark); + color: var(--deprecated-color-darker); +} + +dl.deprecated dt a { + color: var(--deprecated-color-dark) !important; +} + +dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { + margin-inline-start: 0px; +} + +dl.invariant, dl.pre, dl.post { + background: var(--invariant-color); + border-left: 8px solid var(--invariant-color-dark); + color: var(--invariant-color-darker); +} + +dl.invariant dt, dl.pre dt, dl.post dt { + color: var(--invariant-color-dark); +} + +/* +memitem +*/ + +div.memdoc, div.memproto, h2.memtitle { + box-shadow: none; + background-image: none; + border: none; +} + +div.memdoc { + padding: 0 var(--spacing-medium); + background: var(--page-background-color); +} + +h2.memtitle, div.memitem { + border: 1px solid var(--separator-color); + box-shadow: var(--box-shadow); +} + +h2.memtitle { + box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); +} + +div.memitem { + transition: none; +} + +div.memproto, h2.memtitle { + background: var(--fragment-background); +} + +h2.memtitle { + font-weight: 500; + font-size: var(--memtitle-font-size); + font-family: var(--font-family-monospace); + border-bottom: none; + border-top-left-radius: var(--border-radius-medium); + border-top-right-radius: var(--border-radius-medium); + word-break: break-all; + position: relative; +} + +h2.memtitle:after { + content: ""; + display: block; + background: var(--fragment-background); + height: var(--spacing-medium); + bottom: calc(0px - var(--spacing-medium)); + left: 0; + right: -14px; + position: absolute; + border-top-right-radius: var(--border-radius-medium); +} + +h2.memtitle > span.permalink { + font-size: inherit; +} + +h2.memtitle > span.permalink > a { + text-decoration: none; + padding-left: 3px; + margin-right: -4px; + user-select: none; + display: inline-block; + margin-top: -6px; +} + +h2.memtitle > span.permalink > a:hover { + color: var(--primary-dark-color) !important; +} + +a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { + border-color: var(--primary-light-color); +} + +div.memitem { + border-top-right-radius: var(--border-radius-medium); + border-bottom-right-radius: var(--border-radius-medium); + border-bottom-left-radius: var(--border-radius-medium); + overflow: hidden; + display: block !important; +} + +div.memdoc { + border-radius: 0; +} + +div.memproto { + border-radius: 0 var(--border-radius-small) 0 0; + overflow: auto; + border-bottom: 1px solid var(--separator-color); + padding: var(--spacing-medium); + margin-bottom: -1px; +} + +div.memtitle { + border-top-right-radius: var(--border-radius-medium); + border-top-left-radius: var(--border-radius-medium); +} + +div.memproto table.memname { + font-family: var(--font-family-monospace); + color: var(--page-foreground-color); + font-size: var(--memname-font-size); + text-shadow: none; +} + +div.memproto div.memtemplate { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--memname-font-size); + margin-left: 2px; + text-shadow: none; +} + +table.mlabels, table.mlabels > tbody { + display: block; +} + +td.mlabels-left { + width: auto; +} + +td.mlabels-right { + margin-top: 3px; + position: sticky; + left: 0; +} + +table.mlabels > tbody > tr:first-child { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.memname, .memitem span.mlabels { + margin: 0 +} + +/* +reflist +*/ + +dl.reflist { + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-medium); + border: 1px solid var(--separator-color); + overflow: hidden; + padding: 0; +} + + +dl.reflist dt, dl.reflist dd { + box-shadow: none; + text-shadow: none; + background-image: none; + border: none; + padding: 12px; +} + + +dl.reflist dt { + font-weight: 500; + border-radius: 0; + background: var(--code-background); + border-bottom: 1px solid var(--separator-color); + color: var(--page-foreground-color) +} + + +dl.reflist dd { + background: none; +} + +/* +Table +*/ + +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: inline-block; + max-width: 100%; +} + +.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); +} + +table.fieldtable, +table.markdownTable tbody, +table.doxtable tbody { + border: none; + margin: var(--spacing-medium) 0; + box-shadow: 0 0 0 1px var(--separator-color); + border-radius: var(--border-radius-small); +} + +table.doxtable caption { + display: block; +} + +table.fieldtable { + border-collapse: collapse; + width: 100%; +} + +th.markdownTableHeadLeft, +th.markdownTableHeadRight, +th.markdownTableHeadCenter, +th.markdownTableHeadNone, +table.doxtable th { + background: var(--tablehead-background); + color: var(--tablehead-foreground); + font-weight: 600; + font-size: var(--page-font-size); +} + +th.markdownTableHeadLeft:first-child, +th.markdownTableHeadRight:first-child, +th.markdownTableHeadCenter:first-child, +th.markdownTableHeadNone:first-child, +table.doxtable tr th:first-child { + border-top-left-radius: var(--border-radius-small); +} + +th.markdownTableHeadLeft:last-child, +th.markdownTableHeadRight:last-child, +th.markdownTableHeadCenter:last-child, +th.markdownTableHeadNone:last-child, +table.doxtable tr th:last-child { + border-top-right-radius: var(--border-radius-small); +} + +table.markdownTable td, +table.markdownTable th, +table.fieldtable td, +table.fieldtable th, +table.doxtable td, +table.doxtable th { + border: 1px solid var(--separator-color); + padding: var(--spacing-small) var(--spacing-medium); +} + +table.markdownTable td:last-child, +table.markdownTable th:last-child, +table.fieldtable td:last-child, +table.fieldtable th:last-child, +table.doxtable td:last-child, +table.doxtable th:last-child { + border-right: none; +} + +table.markdownTable td:first-child, +table.markdownTable th:first-child, +table.fieldtable td:first-child, +table.fieldtable th:first-child, +table.doxtable td:first-child, +table.doxtable th:first-child { + border-left: none; +} + +table.markdownTable tr:first-child td, +table.markdownTable tr:first-child th, +table.fieldtable tr:first-child td, +table.fieldtable tr:first-child th, +table.doxtable tr:first-child td, +table.doxtable tr:first-child th { + border-top: none; +} + +table.markdownTable tr:last-child td, +table.markdownTable tr:last-child th, +table.fieldtable tr:last-child td, +table.fieldtable tr:last-child th, +table.doxtable tr:last-child td, +table.doxtable tr:last-child th { + border-bottom: none; +} + +table.markdownTable tr, table.doxtable tr { + border-bottom: 1px solid var(--separator-color); +} + +table.markdownTable tr:last-child, table.doxtable tr:last-child { + border-bottom: none; +} + +table.fieldtable th { + font-size: var(--page-font-size); + font-weight: 600; + background-image: none; + background-color: var(--tablehead-background); + color: var(--tablehead-foreground); +} + +table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { + border-bottom: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); +} + +table.fieldtable tr:last-child td:first-child { + border-bottom-left-radius: var(--border-radius-small); +} + +table.fieldtable tr:last-child td:last-child { + border-bottom-right-radius: var(--border-radius-small); +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: var(--primary-light-color); + box-shadow: none; +} + +table.memberdecls { + display: block; + -webkit-tap-highlight-color: transparent; +} + +table.memberdecls tr[class^='memitem'] { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); +} + +table.memberdecls tr[class^='memitem'] .memTemplParams { + font-family: var(--font-family-monospace); + font-size: var(--code-font-size); + color: var(--primary-dark-color); + white-space: normal; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memItemRight, +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight, +table.memberdecls .memTemplParams { + transition: none; + padding-top: var(--spacing-small); + padding-bottom: var(--spacing-small); + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + background-color: var(--fragment-background); +} + +table.memberdecls .memTemplItemLeft, +table.memberdecls .memTemplItemRight { + padding-top: 2px; +} + +table.memberdecls .memTemplParams { + border-bottom: 0; + border-left: 1px solid var(--separator-color); + border-right: 1px solid var(--separator-color); + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + padding-bottom: var(--spacing-small); +} + +table.memberdecls .memTemplItemLeft { + border-radius: 0 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + border-top: 0; +} + +table.memberdecls .memTemplItemRight { + border-radius: 0 0 var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-left: 0; + border-top: 0; +} + +table.memberdecls .memItemLeft { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); + border-left: 1px solid var(--separator-color); + padding-left: var(--spacing-medium); + padding-right: 0; +} + +table.memberdecls .memItemRight { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; + border-right: 1px solid var(--separator-color); + padding-right: var(--spacing-medium); + padding-left: 0; + +} + +table.memberdecls .mdescLeft, table.memberdecls .mdescRight { + background: none; + color: var(--page-foreground-color); + padding: var(--spacing-small) 0; +} + +table.memberdecls .memItemLeft, +table.memberdecls .memTemplItemLeft { + padding-right: var(--spacing-medium); +} + +table.memberdecls .memSeparator { + background: var(--page-background-color); + height: var(--spacing-large); + border: 0; + transition: none; +} + +table.memberdecls .groupheader { + margin-bottom: var(--spacing-large); +} + +table.memberdecls .inherit_header td { + padding: 0 0 var(--spacing-medium) 0; + text-indent: -12px; + color: var(--page-secondary-foreground-color); +} + +table.memberdecls img[src="closed.png"], +table.memberdecls img[src="open.png"], +div.dynheader img[src="open.png"], +div.dynheader img[src="closed.png"] { + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 5px solid var(--primary-color); + margin-top: 8px; + display: block; + float: left; + margin-left: -10px; + transition: transform 0.25s ease-out; +} + +table.memberdecls img { + margin-right: 10px; +} + +table.memberdecls img[src="closed.png"], +div.dynheader img[src="closed.png"] { + transform: rotate(-90deg); + +} + +.compoundTemplParams { + font-family: var(--font-family-monospace); + color: var(--primary-dark-color); + font-size: var(--code-font-size); +} + +@media screen and (max-width: 767px) { + + table.memberdecls .memItemLeft, + table.memberdecls .memItemRight, + table.memberdecls .mdescLeft, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemLeft, + table.memberdecls .memTemplItemRight, + table.memberdecls .memTemplParams { + display: block; + text-align: left; + padding-left: var(--spacing-large); + margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); + border-right: none; + border-left: none; + border-radius: 0; + white-space: normal; + } + + table.memberdecls .memItemLeft, + table.memberdecls .mdescLeft, + table.memberdecls .memTemplItemLeft { + border-bottom: 0; + padding-bottom: 0; + } + + table.memberdecls .memTemplItemLeft { + padding-top: 0; + } + + table.memberdecls .mdescLeft { + margin-bottom: calc(0px - var(--page-font-size)); + } + + table.memberdecls .memItemRight, + table.memberdecls .mdescRight, + table.memberdecls .memTemplItemRight { + border-top: 0; + padding-top: 0; + padding-right: var(--spacing-large); + overflow-x: auto; + } + + table.memberdecls tr[class^='memitem']:not(.inherit) { + display: block; + width: calc(100vw - 2 * var(--spacing-large)); + } + + table.memberdecls .mdescRight { + color: var(--page-foreground-color); + } + + table.memberdecls tr.inherit { + visibility: hidden; + } + + table.memberdecls tr[style="display: table-row;"] { + display: block !important; + visibility: visible; + width: calc(100vw - 2 * var(--spacing-large)); + animation: fade .5s; + } + + @keyframes fade { + 0% { + opacity: 0; + max-height: 0; + } + + 100% { + opacity: 1; + max-height: 200px; + } + } +} + + +/* +Horizontal Rule +*/ + +hr { + margin-top: var(--spacing-large); + margin-bottom: var(--spacing-large); + height: 1px; + background-color: var(--separator-color); + border: 0; +} + +.contents hr { + box-shadow: 100px 0 0 var(--separator-color), + -100px 0 0 var(--separator-color), + 500px 0 0 var(--separator-color), + -500px 0 0 var(--separator-color), + 1500px 0 0 var(--separator-color), + -1500px 0 0 var(--separator-color), + 2000px 0 0 var(--separator-color), + -2000px 0 0 var(--separator-color); +} + +.contents img, .contents .center, .contents center, .contents div.image object { + max-width: 100%; + overflow: auto; +} + +@media screen and (max-width: 767px) { + .contents .dyncontent > .center, .contents > center { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + max-width: calc(100% + 2 * var(--spacing-large)); + } +} + +/* +Directories +*/ +div.directory { + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + width: auto; +} + +table.directory { + font-family: var(--font-family); + font-size: var(--page-font-size); + font-weight: normal; + width: 100%; +} + +table.directory td.entry, table.directory td.desc { + padding: calc(var(--spacing-small) / 2) var(--spacing-small); + line-height: var(--table-line-height); +} + +table.directory tr.even td:last-child { + border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; +} + +table.directory tr.even td:first-child { + border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); +} + +table.directory tr.even:last-child td:last-child { + border-radius: 0 var(--border-radius-small) 0 0; +} + +table.directory tr.even:last-child td:first-child { + border-radius: var(--border-radius-small) 0 0 0; +} + +table.directory td.desc { + min-width: 250px; +} + +table.directory tr.even { + background-color: var(--odd-color); +} + +table.directory tr.odd { + background-color: transparent; +} + +.icona { + width: auto; + height: auto; + margin: 0 var(--spacing-small); +} + +.icon { + background: var(--primary-color); + border-radius: var(--border-radius-small); + font-size: var(--page-font-size); + padding: calc(var(--page-font-size) / 5); + line-height: var(--page-font-size); + transform: scale(0.8); + height: auto; + width: var(--page-font-size); + user-select: none; +} + +.iconfopen, .icondoc, .iconfclosed { + background-position: center; + margin-bottom: 0; + height: var(--table-line-height); +} + +.icondoc { + filter: saturate(0.2); +} + +@media screen and (max-width: 767px) { + div.directory { + margin-left: calc(0px - var(--spacing-large)); + margin-right: calc(0px - var(--spacing-large)); + } +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { + filter: hue-rotate(180deg) invert(); + } +} + +html.dark-mode .iconfopen, html.dark-mode .iconfclosed { + filter: hue-rotate(180deg) invert(); +} + +/* +Class list +*/ + +.classindex dl.odd { + background: var(--odd-color); + border-radius: var(--border-radius-small); +} + +.classindex dl.even { + background-color: transparent; +} + +/* +Class Index Doxygen 1.8 +*/ + +table.classindex { + margin-left: 0; + margin-right: 0; + width: 100%; +} + +table.classindex table div.ah { + background-image: none; + background-color: initial; + border-color: var(--separator-color); + color: var(--page-foreground-color); + box-shadow: var(--box-shadow); + border-radius: var(--border-radius-large); + padding: var(--spacing-small); +} + +div.qindex { + background-color: var(--odd-color); + border-radius: var(--border-radius-small); + border: 1px solid var(--separator-color); + padding: var(--spacing-small) 0; +} + +/* +Footer and nav-path +*/ + +#nav-path { + width: 100%; +} + +#nav-path ul { + background-image: none; + background: var(--page-background-color); + border: none; + border-top: 1px solid var(--separator-color); + border-bottom: 1px solid var(--separator-color); + border-bottom: 0; + box-shadow: 0 0.75px 0 var(--separator-color); + font-size: var(--navigation-font-size); +} + +img.footer { + width: 60px; +} + +.navpath li.footer { + color: var(--page-secondary-foreground-color); +} + +address.footer { + color: var(--page-secondary-foreground-color); + margin-bottom: var(--spacing-large); +} + +#nav-path li.navelem { + background-image: none; + display: flex; + align-items: center; +} + +.navpath li.navelem a { + text-shadow: none; + display: inline-block; + color: var(--primary-color) !important; +} + +.navpath li.navelem b { + color: var(--primary-dark-color); + font-weight: 500; +} + +li.navelem { + padding: 0; + margin-left: -8px; +} + +li.navelem:first-child { + margin-left: var(--spacing-large); +} + +li.navelem:first-child:before { + display: none; +} + +#nav-path li.navelem:after { + content: ''; + border: 5px solid var(--page-background-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(4.2); + z-index: 10; + margin-left: 6px; +} + +#nav-path li.navelem:before { + content: ''; + border: 5px solid var(--separator-color); + border-bottom-color: transparent; + border-right-color: transparent; + border-top-color: transparent; + transform: translateY(-1px) scaleY(3.2); + margin-right: var(--spacing-small); +} + +.navpath li.navelem a:hover { + color: var(--primary-color); +} + +/* +Scrollbars for Webkit +*/ + +#nav-tree::-webkit-scrollbar, +div.fragment::-webkit-scrollbar, +pre.fragment::-webkit-scrollbar, +div.memproto::-webkit-scrollbar, +.contents center::-webkit-scrollbar, +.contents .center::-webkit-scrollbar, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, +div.contents .toc::-webkit-scrollbar { + background: transparent; + width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); +} + +#nav-tree::-webkit-scrollbar-thumb, +div.fragment::-webkit-scrollbar-thumb, +pre.fragment::-webkit-scrollbar-thumb, +div.memproto::-webkit-scrollbar-thumb, +.contents center::-webkit-scrollbar-thumb, +.contents .center::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, +div.contents .toc::-webkit-scrollbar-thumb { + background-color: transparent; + border: var(--webkit-scrollbar-padding) solid transparent; + border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); + background-clip: padding-box; +} + +#nav-tree:hover::-webkit-scrollbar-thumb, +div.fragment:hover::-webkit-scrollbar-thumb, +pre.fragment:hover::-webkit-scrollbar-thumb, +div.memproto:hover::-webkit-scrollbar-thumb, +.contents center:hover::-webkit-scrollbar-thumb, +.contents .center:hover::-webkit-scrollbar-thumb, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, +div.contents .toc:hover::-webkit-scrollbar-thumb { + background-color: var(--webkit-scrollbar-color); +} + +#nav-tree::-webkit-scrollbar-track, +div.fragment::-webkit-scrollbar-track, +pre.fragment::-webkit-scrollbar-track, +div.memproto::-webkit-scrollbar-track, +.contents center::-webkit-scrollbar-track, +.contents .center::-webkit-scrollbar-track, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, +div.contents .toc::-webkit-scrollbar-track { + background: transparent; +} + +#nav-tree::-webkit-scrollbar-corner { + background-color: var(--side-nav-background); +} + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + overflow-x: auto; + overflow-x: overlay; +} + +#nav-tree { + overflow-x: auto; + overflow-y: auto; + overflow-y: overlay; +} + +/* +Scrollbars for Firefox +*/ + +#nav-tree, +div.fragment, +pre.fragment, +div.memproto, +.contents center, +.contents .center, +.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, +div.contents .toc { + scrollbar-width: thin; +} + +/* +Optional Dark mode toggle button +*/ + +doxygen-awesome-dark-mode-toggle { + display: inline-block; + margin: 0 0 0 var(--spacing-small); + padding: 0; + width: var(--searchbar-height); + height: var(--searchbar-height); + background: none; + border: none; + border-radius: var(--searchbar-height); + vertical-align: middle; + text-align: center; + line-height: var(--searchbar-height); + font-size: 22px; + display: flex; + align-items: center; + justify-content: center; + user-select: none; + cursor: pointer; +} + +doxygen-awesome-dark-mode-toggle > svg { + transition: transform .1s ease-in-out; +} + +doxygen-awesome-dark-mode-toggle:active > svg { + transform: scale(.5); +} + +doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.03); +} + +html.dark-mode doxygen-awesome-dark-mode-toggle:hover { + background-color: rgba(0,0,0,.18); +} + +/* +Optional fragment copy button +*/ +.doxygen-awesome-fragment-wrapper { + position: relative; +} + +doxygen-awesome-fragment-copy-button { + opacity: 0; + background: var(--fragment-background); + width: 28px; + height: 28px; + position: absolute; + right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); + border: 1px solid var(--fragment-foreground); + cursor: pointer; + border-radius: var(--border-radius-small); + display: flex; + justify-content: center; + align-items: center; +} + +.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { + opacity: .28; +} + +doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { + opacity: 1 !important; +} + +doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { + transform: scale(.91); +} + +doxygen-awesome-fragment-copy-button svg { + fill: var(--fragment-foreground); + width: 18px; + height: 18px; +} + +doxygen-awesome-fragment-copy-button.success svg { + fill: rgb(14, 168, 14); +} + +doxygen-awesome-fragment-copy-button.success { + border-color: rgb(14, 168, 14); +} + +@media screen and (max-width: 767px) { + .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, + dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { + right: 0; + } +} + +/* +Optional paragraph link button +*/ + +a.anchorlink { + font-size: 90%; + margin-left: var(--spacing-small); + color: var(--page-foreground-color) !important; + text-decoration: none; + opacity: .15; + display: none; + transition: opacity .1s ease-in-out, color .1s ease-in-out; +} + +a.anchorlink svg { + fill: var(--page-foreground-color); +} + +h3 a.anchorlink svg, h4 a.anchorlink svg { + margin-bottom: -3px; + margin-top: -4px; +} + +a.anchorlink:hover { + opacity: .45; +} + +h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { + display: inline-block; +} \ No newline at end of file diff --git a/docs/images/nvblox_logo.png b/docs/images/nvblox_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9cf09f408863a4f11990808dfe42423675b6013c GIT binary patch literal 1722 zcmZux4LB2M9Dir)T4a=vJ8Y3qU8RSHHk+?d!mTbJ*R}NFBSd1>#x}Z=6xEYLK1=Gz z(upG<<0(eba%H8mImvVz%PlrD+aZ;7@AJIR`~Kgr|Nr;<|Nd`^kC&UK`uFMp08I~f z7Xko~sVM}&zndC%N8b#ZGJXqncJ}dbc1A@-M+Sw49|XYSe8PFG`+dA&Gx6zZLWz+G zb@g1Ky}!2Zk!P!y6*}G24T#-P^FbrqdgYJn(vrfOn$nv~j;B^I5zHi%4AM8)Uo>c9 zrd)4%_tZ#lHBvl`9p*utuC-gQ*?iunO#X4?&KkZ84q_92jp+-!f>t5#D>Kp2j zgC2O^7)UXFu&?lV1|rCHhiRTkT1mFoxKqo)42fQF+3x*i)PMC)M#~>=d>)Eek?6YC zF$uoF=AzFQU8{gt!rGz`-0WziXpt#=se)~#tsg%&L??5(-^>mnb+LCT$> z^d$vU{Sa=%#KeoLE9MN9LG@p+lv|;h<16cV+^cSQ@(#&~RZT{xft*M?b02q(M&fVFwJIPN6B9O}UyeuiJp z2wWeq=z2j4;k>iUBS=9(uX+@?x6}G{(&}FkcqZNvqK~(8A-IMTTr3-Rp32|X(8wmY zj7jd6iVla1OZ_{@q-i(**BAkt*2s`oq}{P<^{K!-}{61QBT_FpK`#HXDOuY0!7w|}E2tNZFedh+qXzm_UewW|CvT#t2cLk1&4APV#d92DB&eLGAl#{2LvH9>XOiaUK zWWA#q;YoSujnY`PZD^^4MOWOE$wu3@-_6H&O{#tCx90F`LyV~^+iF`9+L#^Hm2#LD!mG-L>PKRy;$Fenv0LTzmy*31itWx}^IDt4>$x^+N)Ru_F z@}j!Os9FSyqD*l({yEOsGzmN7r)bE-y+mW>6CruWh9#o1QJRA5z=?!?N~PLNK;`xw zQfMnrOi$KB>RK_(6~v7}LHq(R=K~mQa&0cPJ?)yC7@ArAWZ=cWi`^^m|2N>ypuMYq)3JUZK z(R#*`>V2cNZC;1E0f5d#`}zh4`TC;c5{^ej#~cB`{&MG1T=52Yf)kMl2N#5$x zR14Z*?Be3^y&?=lW7*vIM!gI6k9;F?#9Q8V*pXjSaj6$3 zJvz51yi|kKtKsq*7vdG5y!w{VC@xO#JkmauFW?id@>Ho617oXfOcSzUPd}Au-|}r- zVEFF<7?>_81PY7SXoH9oL3{iW;|6*ra7@ZVbqN44haf+n(Bu&bf9tV+;+ppO9VC*O z+iG)9U3~Z z8B3i#6`Qn9i?b}ropVlUqB;ciwx{|kd+f3%tL-e%1Fl5hUc6ixGxMw^Q)L-Db}%M^ zii$wh3F<4$Bp4S|wwE_G!%cql*u9fo0W_iRf` zDoXL?)~tA%L8cazx=-HslBHLR0z@S7+Gw&>u{_#n^sJu9PR^pRz3rc%M-h%BCacP()9F6aXt07X_CzQC~E{qUP) zikIEfiBleoYSED0{IHUeC{Fmnt%g7e>=tOOXL={lG=ltkw)j~Ra-|_{$h@6wDBSmD&UPAr6e6ev` z`v|*MhXIJ7Y5>v6S(IWa>prdhjFUBMG{Uqp+4?I`s}2!_ZH1W~VbXSXa{i=`nbOW; zvR$A3-x&6SaxTLqc!!NJ$4h|0sc9vpvpwkLyA?r5$y&c{q}aW+e2=in>jtjOf*?-pP(SDrNFDQ<=xJ#?Cv;I* zT_V8#I{p?@cQ4@HbI%|0THIjsELr8sCM@W>c&hPrQ%|2;TNQ8yy1+8hC(m)dA*7ei zN6@Ywnp;`Q3HEso*K{j0gW#d=llzTP=F%O30f1H*Xze?n8SCz9gr9B9or0xckU!b4 Ih7`&C4|=gu?f?J) literal 0 HcmV?d00001 diff --git a/docs/images/nvblox_logo_32.png b/docs/images/nvblox_logo_32.png new file mode 100644 index 0000000000000000000000000000000000000000..738a25af3759502dbaada5d55216185d2b0fcbdc GIT binary patch literal 991 zcmV<510ei~P)EX>4Tx04R}tkv&MmKpe$iTSd{TNIQr)WT;LSM2k3T6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfbaGO3krMxx6k5c1aNLh~_a1le0DryARI_6OP&La) zCE`LRyDD_Oq8EecM+h;Anfjb4CgC~0?&0I>U6f~epZjz4DLIn?K7n|a>4rtTK|H-_ z>74h8!>lMN#OK8023?T&k?XR{Z=4Gb`*~*ANT=qB!^A?Njpa6GMMEWy5l0kNqkMnH zWrgz=XSG~q&3p0}26NiVGS_L2Ab~|JL4*JqRg_SMg($5WDJD|1ANTMNJARQ|GPz1% zmr&ZfWu!aJd5vJ?WAmIZ}Y8Kc5HQ&*+=7KOtZfqiFR_Z7TPTb00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3ljhU3ljkVnw%H_000McNliru<_i%H6dBX!0ZRY?0o+MMK~z}7?N%{v!axw5vm#k8 zXppP;5tj1+Qc&=OBoCmYqTv@*bbdgRCs0r%A3*s+B&ZM#MU*1h6!=t|f;LK&bI{BEwfPv#wot_{3C@x{HopDh02>bgw@+Iyi6|5t0B8+t#ycc= zT$5M_muxWGg4RY=3K2Mh9ydpM3V1W-$mr}fzRFxQmcZ*nX23oYlKJpe{ZLqeS)KXU zcRK&zdf@P?FqvaB z-qmiz6?ZjNaoPu5n~#Q=E>{c*Kotj0_C`fWx&vlqis$#cli)h28(fppO6VWcpp;mI zS($2?FkP<1^A0IucTQhRR=)nPNpSK@X7&GC_iRd_M#3hdGvPX)69o1UlY$3_kwkZ4ep*p&bP N002ovPDHLkV1kG@xMu(W literal 0 HcmV?d00001 diff --git a/docs/images/nvblox_logo_64.png b/docs/images/nvblox_logo_64.png new file mode 100644 index 0000000000000000000000000000000000000000..69b0b0e20dc32d9039512e89ef8b7ec2872135f3 GIT binary patch literal 1084 zcmV-C1jGA@P)EX>4Tx04R}tkv&MmKpe$i(~4569qb^YkfAzR5EXIMDionYs1;guFuC*#nlvOW zE{=k0!NHHks)LKOt`4q(Aou~|=;Wm6A|?JWDYS_3;J6>}?mh0_0Yan9G%GL;XnNI5 zCE{WxyDE0SB8UL`5XP{~EMrcRlJFc~_we!cF2=LG&;2=i)ttoupGZ8*46{nSK|H-# zH8}4RM_5r-iO-40Ou8WPBi9v|-#8Z>7IPWeK{ zWtH<5XRTagt$XqphI0DKGS_JiA%R6KL4pVcHIz_B6){?MQY@rsKknflbo>&z6mpfo z$gzM5G{}x0{11M2Yvm^=+@w$(=z6j3j}f4I7iiXP`}^3on zj20++-Q(RooxS~grq$mMBNK9m1Ig;600009a7bBm000XU000XU0RWnu7ytkO2XskI zMF-{!5DqUM$&DPf0006@Nkl{q2x|OlSIchm9}aUf%%#i}BKJ+vYr2Z+HLz*gxL$UT^7-1aw6}tCK>6>x?*A zsx_ypW&sJ%I{$QegJc9;UCP= zRwY8t=SrT#j->yMtTH4ZlYr((-%kMm&sY7%oEPV{b38Tmg+RA|ne*a2SAty=;Ew!i zf+doWtJMBw{jnG?ZCe(QfYh|b#DD$cv)c!a^&i_)gh(I(>XF~5_s!2XvgfHVSIWa#8cdsfH{h}|I0OPb1OaVEFEmy%NI zJPFWdfIIis>S|K@=gM>b-{?1VhDZV`5YS3OhzNI1YEOb%ob-}b>O2X^7%i)r`!OOy zX|7#ahB5(sGt@l+N!bu0B6SZD%LefO0e?q;HyeK8ZLq0103@JdTlOD68wsE&iqa-+ z=xwU|y^W-G=zb{Mhq7H{J`bw^p!kna2ld!wwjU$Vi|4ET~=dZv1{r~ybU;pm^{ty2P zxRX5p`Tqrf{@u@!*uVa-|L?#2|9}1U|NQq&h_>M>o4)w#Unuv_)xQv^o_^cEQ2t*C zlFswr-zKfrbol)}78|$)o)6QvDVyT^PZAz_dO8zOI zR>k;l72Kx-n7l7FMb`-&!e zhW;;v1J`}i72uCluSpoU12;F}DwbZcf)Z>Ecfd*oNbsq2@|mdG;Gpum~X%s~=H z|3X-HDC5sOGSkN6>Oj)WN7gAe%s?$nCsa%)f~%s$xV!9i4g+nmDb2l+`CL(YkTaiQyjxjpNX+N9_mNn$FV+(P?R%YU6%aBp!_yI zYSQ#{$~hjEl6%~b<3->Bi*F9el`LJyS>i1(#peIr8$$($<~QGOCsYnX-qSx%q)+B&^Zjt|cONC%*+O z?2Bg!RA!>bg>G51hub=!r+xH?aM7T$WWzCi>s_Mg4+U1tFe=axep@8ZUc+~ZNPyh4 zd%qLMy4g-s){%UD+2h&t1FvlqT_5l~Pl-}MqeI(J%!M-A?5&;Vj~$_pl883^1{F@b zmbsuT*k2;;RtC64vlIh!%2HgefxEI(zhA(wPHm_S?!bYLHejYi3EXU`m_G;=EAetD z*a$!01we_>uIp}hpBavB=tGGGkXA9rVwC=Y>0@W~6`@LJX|pItxcD+(7DpGq zr~+sJ_P64%$nDuX!DeZXNIzoy?@_=r*G{IS!i4p;TS!S>jg49#ln}_bF(3%+XoB}e?DqrLp3PLdW9#-fGEPQc zL;^trxzC`$SeoySVr|x=LN5`HHLqFw5$e6RGv;kQjozM!t6=`=994HPUi$~G8ZfvW zKtP^Y@Fq_c)T5TlgIRBJ<67_J>P&D+iPP4-@(J{xxCs|fQ123mi6B)aHdpjL>w;C< z?=la&2*$*gzviGX@&^>TJh+CH;2(ZXdV`XDUhu-Zr zV!@xCT3`++DhhuzQOw)dczw+h7z**VAiDd?|7E;F$_MYf$L!4>=ahoWvsMmTckB~a zP#Rz8Aq0ymnnCojE;7MHmawDAQ^A%swORzN-r_ z?_xC7E3)b_JRU_uv3%P2F+=ZwR*xycAI+jL^PyjH2LjA0m`+8#jQP<o84k(RU zoZZl4L_HW7DI0>{owwZ)Jw4KfJlIXw>=jy9IOq~yG9{wM1$=+y|M#u!%NZ+=G-3+0 z&t6L!JwE=bnj8F%;McY!BrNUwfc$sPKgg#%>A3{U$7U!bW6uK?tKFFC-GCHOSO)FUm2seO1vZpOM?FQ;Qk&W^9YfC?iFi%R;W87uJl`u_)S3^9RflHp1+jc( zih~Zqh?OCA(mf(bNFZhMAr-&1q5Uhp^BC^)7+?BlM8Y`&dPM}gmc>@GB$sd5<`$E@ zBlYXCi;!iM@z4QM!nW_wu5~FW?9UQ6Q%NB8^j>#cM9D{Kfy-oi1tv7;R~(2FVn(D* z4r-vC2bvy_qiw6LzQnr)P>LE&zI+0gqu$aj`sy_4l}L)RZ1@K(8MtQfcP-Gl{o2>^ z&LLrf1!vzHH0@OaH|fzBr%361@YHaEUa(f#m+y|eN#PTN`C%RSRRLxE%B%>+0~AVq zV(W*e7Yhgm>x=Iy=&v?ly?01$IeIr}O+4`veBvTcAJjW}h~Q@%Q{mNEB842j+jJ=G2TTYnA0EEvYzZ4qxqOWx zZ)BB-lJW<`C4~}1UH5!~3IS-3^|Fvh(z@(d0(815ntyopm3VJehJ#Yza=|{5 zLGt=Vv$wIfltU5(uKO#2GV2Z72j~DBQFfL@Ph6K{O?CHJZjyXdoZi{dyPkxCXSwv& zci`Gg=00F5Y~nkI=cgl zjqJG2GAyn}0o{$3`Pk5&p@TVVHhjJYTxe@RfSx@%gLx_{A73_LYWyrn@l>yPgP-n07 z9>t)M8OV}IL34pyk9qj-#uZNbOy$j@=#vpfnDg_?hg>tfb4&g$DxZ{^fwkVQoLt$h z+D$xVB2C_B{!P^CvTo6hjCx5!6qS%&-#~y_h>Jjvm0K+n*U)R;aS7h`H}X6-bSw*C zW>5SZd?FYGO$o~d%2?)+rZq8Ig3g2FAcny(TX9XFkRvZsozTtFj-A-*8gjR?MAri%@hf9BVC~>yK8weo3#y(e^d& zGUm2@(Ct^*GuYDR8|94AD~qD?`>@}%sb#IZDDeHuevXxa!M+sfM$s^>IR;n9Z3dB| zJ^z+$Yw6}Eu2y8;N+}~sxhvy^xU3MfJYM^>&ageMC6y))L7dvUCQr+UfJ+rmU|q+u z#k2!WCk|$adId|#(SUgr%QDvI`4*FZ3eb$I!PgDzw>vWtz6*#Ajxbk0Vq6!aJYFRP zE4x;eP#~M1n+S;Wu0oU=%ljvByv%>)&KN6w2;{5+uR~!1UO`*6a~R+XfoTx8BX>Wc z`zqZBm>L#R%dvSf)Gjr(tgh`zLNy+KVzD)1!gNN>4QOxAzPeh}@)%gBQG#|tZA8F< zkQ?L>tXkTMxu__YNV8U!Drw7M(!KYu9ODddw&s?=)z8gtsrWPj-2n(9V*Ju<|9)n|x*7?44>xHHuQ_fXE)}zHtq97r-;U*3en@o>O%wQ1rI1Ux=SrK#Yb{E-A zcawWBFS4v-j#VzobEMchbn|FeqEBMUC^_)fpLQ#_b!i>^a(T4Lva zqmkkY8CN}(p2d!V)rz3Wy2N(lkcYTQjMaq)*t1kWdMguvbz^^s&%ieVVqN`tEoWT# z+-QkvXi&U)#^g=*DsGN+J66W{N`(!6At+dj1;2Rvr~kbC%#{V!jyCw2BUAojEuQ>X zsr)_Xea+UcQP2O?8OlhCmc=r&)J4aR-RehZ?IvTa)@9bxs zjaHu=&?w7ae4bELv;xRO50o8K$~&pVT``SMK*zatE2i%celzLNN2jS_P6_MuKEaxo z{I$MH*cKS8Nel{ySZ!ns1=#*hV#RwFRq?z&LOPWV)h_&hGPH9S_ zPX6j1_fj-S-}!rXWx~!KN^}w_kc%3gDdCxPzi`~34H>xI78r7t9caICE{aCgY`u*O zk;nZaw?t#S(ZF}7OQI#uEa@NIT{;>&Kd>gj&FD;=9&~b;7@7KIp+c--XNNM|kL{~B{(~j8}7^FLTa_wKhw(xy8hX}Fj3}_qAm>Dk|NnV^G2(hZ}GBpqM9&2MIp|N zzV1lD8rK;y0E_@e;xusW@)bgueE3b4ja0?Faq?KZ$Ci{SXV#kPrzOW z+i#d_j{VwA6p=6DWMs2vZ{O9F^$?N7EmPwSPK<~deOQbr_SYl<9JsAqoq>!xUN@(8 z7q(-}&?6_KSW(rH3FJ;q9P`SK`ScEJa1=aQ8R1|v2@)_Ol4pR|gzuJ2-tL=?1w+3S zYLeD7htio)M+Nb8w7zcpeQRNe_;IKZqABS%hP(8XTz&wdr+g&$qIZ%?&IA2=onLp` zU!?oR2PJbY*M5ux^%$nbJ9lQPHx2ryZP6ro^T805p31+GvLS`2ekuQDnI z6|0X*qv}l|f_RlUz=*$FW&ZJYJYM$7==nnEFzAN=*@+VmP({$%!_`1HM75>0(;g-vLNID7-CRxxPa>G3@%1 znu<1?>{wmEPnz1A)#Q>}s&OJ&aYdYd0Ls-`08vB`IPUAd6{jQb7hZz>bGrjWRt$6y zgO4{9hHT>dP1C;tbVP){n>0|o+(P(3RwI}@@$eGho^2C%&yV3XS)iLsh+2yfu>b^d z7N~A8BJH=kGym<1wd-*vmi?yKa(tt#X={y@t@e~f!!8+<7c^8XkpAqdp(IOCQgmrw9*gSOF{-ySKG;36ti8rKp0#pY$2X&Fh;*j%cy}n6>nuFYb^>56D zM14BTyP4$p$2_pN6*|Ed0`4&P>D(v}9W)1s%4+(!`HGNK z4{)U}>lMh8*&`SC_BNPCd#(-k%-ORP$f;ts9x?B0Ld4s|ptYNeC3aD6ctP{>jMoEmB}L1Z>!$Bi6Y zf5~6-i3@$rwg^!;Xy;kK(8(MQWwLBtBZW1$5WA@)eS>)_XK9YPvImHRH~mg)E59rSeVA) zv1*|Y?_uG?az?I%&g1b2{Xz~d(55-n)-~u4_zF7t&{!~mZv&a&VT_F)S6tu;Ryq(h zj8+K3boLYCBW9$a6mLHiSa6vqS~bii5!O~P^nE`}+7Q%zprxTn>CZ{|leZvcCoj=} z@H0-Sv*$>7e(NAM&0SC@s4Sm(u|s96{4~5p4>H~4VOS3u0NF1Qt*qiX12?-D9J|x( zkyyl*fsdc(GU9DLXFGLz@hXUHh`HVoScAVxqO&Cq0~npyi3hmu~%lSNQ* z(KUsRmL>xuE@98X$T@U6(ZC%apnSQ~z7V)tt8$XRG?s_>wv}*+Pp|Kl9DYJ1Sa-ca z%$65z6ZUh=PG-C96>xBQDLlZWvIpAAhn=8Kli5b>O4+Neg>^6zc1S29Gv}!g02G7g z%*6vhAk`EkZX3TeKc@qu`Kwt#aHN=*gYhmOe50m<9juq|Z8}J;VhLS|92sNqiWaX> z+UZlra|JZgwD}(g55zp!{RV&_H?a^&ABCy{VR77|1T9cd0;fwiO+D%G0C}lrU%ugl zA>wc7exuCUhK6+tUBk0K-U9x$=95DJZquua2P#!mOurt{9t#qvx-$>2p-r-;jW3q~ z*@uRgoTn%NS_%x1{`km|0A=+=gajgCH%sT-kZ}Z{77dNLVH1dg_>&a>S3RH3wWCQ+ zJLVHojSX#CZvaT%LVdHTUqqSJ;dTn|enWnA0zX&?J+F5!UE?4OlJ)K|_nt6{=_it? zqzM)NMD-U7g6B!$2i?Dmu~evgOjY`>3-9`@AJ*Zsv5FYWqCv!r-(Ypc?oBtdCH)-p zwyc+nP`@(~WfGWgPqK{PGTuuh*DA`qiU?!^AAi5W)oKESg-sZfKBgk*r-5=dLeHyL z5l;ZJWJf>6Je)6l{2SpN&E@u%v2j&=2}Nek){|t2bNMT&tDpgRtVmBYfE(m_y%OV? zW#w#s??MwFneI6lTMoxv`SwLY7!1Pq?OV~3>`(YXWg^a{hCS7bc5UDvVIj} zrz5e3)|&*}#Pd>Oznn)QHQh1pm8YPAyG0>tL`vGVTCqR;z zA`mTok;OtB(1R6rst#7$=xt>BSbk+kH8mQ=;}T3mK%YaFKCS#ZoG8d6MrBd?ZGJC` zZ%Vk_gtpKHrJ;SOE54q0{<9+jpZ;^}Yyt;V##OUiNA{^=?lK#|o7FzTbS+>@$PB`)fo9e4-VHJJX0o*`X~R^#yiqE??0odUUKAg3>VG z2Laxzo43-BB%WFXrTKREDQ&PIIh-FLKwo0=^Pz3R^1aV7?`HpFF`2|{*G*ICM~-wI z72#$di5ero(G>^2?e>HmpIYiq5=p7jv{vhCF*ml#TJUzV?-wqI$>f!<$+1qF7Uu5f zf1RS(kV%I%5P!&SfPDeLZU)O85Z=%330!T{6c42M&^=9J+^MPr-{% zzqt`L6t0ml$+dUAht|ezUZ(i=rwb_br%wa_&F1)OpPc3Gno7cr#MBSLQo}H{wt$j? zB(Ijx7g}3kds=F4$|6PB5Fi&J-;Y;gvOIBP#oxkbNgFpTV?)8bnOU>Xkf{ln4be!H z7C6PogFoJ=4v`ukbNvwcF5D%i{uYXw(-?%;-C?5IId{{l1A9=F`@-W0R*F|! z5Ea!6K>P#ja*YWOM2DG}&>7Qd=@Ch?zU&VTNNK$K;S?joA+ZO*4FIS=zw9Zhuw9UH z7|h>0n5I!z_K$V!NeUY{kR6f#fgyTsomj2wH1nVj=*93Uh5|Gh4Ed?XlU;v8lg1Ws zGRj#-`P%%<-5sE2?Q+BP22E9f;h}lI>527KAaiA5MaeCh%r?hMNtwLlb{FVp$@BZ^!>~9zeOAJY*X5qPm}m&u^Ge4vbB{Gxo%^Nm6oIUxU-okN z$&9eiH$>ef^$n=T3*A9TQ|nm9-R7Q>>aWu)tsmhon99nJ++hA_pAkU+o-3pN0PA?| zHZU3F4XyviQrHnY3=&T*<%0ti;wSuFNme9ebz9zu1OQ3727?4rc6(#6Wbp~tkHkA% z3|p=bx6$;~8Z`vDDUj)yL2P!f0esXv!RB={g|Ev!J4!0X*&MCLOw@7poLxOq1*`KI zJ!E=4^%8xk{tqtF?ds;i6P$xI<}v8-tLPJDE%=X==n?I@$DJZ8cx|z{kQRuRe2-8g)&2>)t4ODgI$Jt}8kwNKFpbBazN2&o)paT`;q%#Y8rjaa0hv_djUGEc^?>uSfWyAve~=yy>uY)Z`hKns-*gOtK;N4^lwRz z0|aRcE!gcYye5a7&~L6xSX*&5b8z4mdk){=DP>_`xGCgR?i=WDr}SomU$O%mbZs?I zYEcY=cr!oXAAefSpHg>aT?52klf$f{X zZ4!ix+F#?OtliBRD(;-!8!3dU0s4DblE(|Z*?M*#y&F6*jJp!Q2)yjWF}Wz zNa)nlAQOSx^@Na9kg%=1@l^`FpKfRvuO)`?wgBSNH+12dY(p3caFTB|$2t35mva9D z&QITEyXqC{vNP{B2HOg}4q3WS>p2qc@i7!dY@XbZ=-9@gQzrQxAcK1Uwj`kjFHDTm z702htEPk?lRXAI{&6uNXcHzhMB4AgGHK?ZOKyMLlk?dCnL}?iwn+~t}Ek+Y0T=syK z^~cl!YO{zyht)kX&5Z0F@f40(kxziw#pQjl zRu8Rov*K)%Eo)k9jsvl)n0fP8^!%n_DaXx-*(jtm1~01b3ilS%&;iM>HeC2T1y8+IgDZmZc`Ko3tE7yj+rDqS-H9>&RajbC9jpkIVcRS-bI?zu;W922wBU5V z@C3Oihr`~@<%H4CxpR{A{2T4w8qQ4LgUDm!zxQi)8Y8GpEwvm-ecWgbI@Ff3j24OBI?9i9>pJmNL8;|zi6xi zacdmZGV5`#4SMv#l^)6>CKqmJH*0Spc2Y9rJ9~jv{!q8A6ZGE#dMGfRe|EpMY3@gL zV2%e;DcbNX#pc@MrxTJD{Z*ZZRq7(DiCdsdlFJXdDy>x`~-UyG(R?(O}na1x$=1@#XyaMGXZd+ zMApnuSYykSw>NMHK|uFC#lb zHM!AoS^9@4r5b9Hmur;c;7s|S+OOrZ^k zLBpjUehxqHk9+B#RT(@vg%!Lr5AA2}ATG5iE+L7HAQKe5Kw8bh$s380TwLF!7Jr-l z-S;=_Zb(NC(=mv$r?o!8FniQj!_nX?vxX4RORnQq(|VuU11Ju8JWvlb_@2p`1y_;P ze)=OF<3|{9RFvr_xzooW8=PyBT4|uydv$(>?gA>o15_ICH3WRv&LR@-jFItuWm@>8=ImP?L*U{dnz)C~@xuiM=*DlAAJep>Wa^-aI??J_aMOz zy7P94>DmPex%$|(0)l}WXKNUX;HH=pz=D}557|FAma-sQekJ?eaDZSP_4}olfk{Cf zKW5RoauM+e@Ta0&R1? zs~gr>kiqrD`qA9TBf+crBt2t(KDW!$&N?J=JMIjS8rIi8&eESz0kbencsvN=Wh}>U zqVdk;+j`&MlQ#=k6L1(o{5E+FGPe7)20gkZ3O;v-GT#O%{KDtTL}_T%PN&HFK`23bvwY-6@*ZuR z>9Jx+Rqo?9(aB36Shv-&dEvPJ7$oONBEVE;XMOS_wFV7qv6XVYgDwjB{m>$x#i}E_ z-)elgd=PK5zJ6FY?#~o|w-&|eXGl7EhJDQZD9N|3P5)ax60JZhq5yng7d{=}PR8_= zOa~5usBefFivR-$BBL&BNK;f?s_Z;{qLPzwht3s0`Ef zMv%Hk&#dLt+hm^eo!TIEmYv}N=Wsrfy+1s3<1zh<0e6DcROOhQ2Mw3u4SuZC4P$u1 zhjL;`j`QH%EojG80R4Gu0EDAq#x`%e&Y{1=BK#xf;gt73KfSk9Z|Q(^i#h&GszM}- zyFVq4;RLRtIXK_61{h7nQOeV!Dq|7L(i~$(IcHa96bJ-lGJFuDg+!4v7!=S_zG^Y=;b6<|mpZwGsG6(pfx7#ap;gC?84S^!#=&P6fhkPDT=0zdNEB|%J2jqOz}<-U0>YmI6P~)20Cw(Pz=sO*6G4*M zfo*@~d3bjh3ltR~KwMGu+YrNtdNdyCu05B@jKb{I$Y@p%E5(5rDSMLyK`@DaVbADj za{ZVQs)V3YHdwi{jnN4XDu^dy?v1yhwI2ivynZ&DZ#`)G#zB=U2=e753(VIIpsyvm zMb^!@>6(cd1YBb2JO>IC7-;8m)T9*q*p)9Vx>a|PyB|;?`^1s;H5tr9fFy$Gy&~g- z15v^$g}gLMW8wsjBwa5VP>lG2Y6NCR;qkSxjSzm)d)4GiHURcmVUf->V=T2RK`3nX zePOYD{~`d1W}2ixEh&Kh6?jN2%GBl8$Xl$-Iv;X6)~gN(K=AXRV6+K}h4w{y}5{q$~2=9vN#$EuJP=G=c;) zKR-nZ&B`wACk7Y{npQC9YU_1@G{XY=DOt*87c>YAobZa>&RT#<6r0#YM3F=gXY?&Q zLINE0_^y72Tw~yIUApFma?77{Ls+-NWft5evEIj}aX)}Ue^&o37aq+(gb2ZBz5~mlAMNvL%DP z<71zxh1;CR@kYYaTY}jY;E8?|7brB59~hRcQ)2OiO&|GLZX*rllMOU8`;TWxc{D06z0Lt><34j7pLYxEBy1@3~u%hU)F8DCI1xr)liBHH+= z$B>;t@4IVaN_J+C>2ea6TI(Jwq?!k#2gCZMr4P~@-~RXJ35xzx>#hfS`Dm=LeIAmN zGDP|uTJT+g;n-5DLk4kn{bqavsbns^^4pccs~amrx3fk0=F@$s&l?n`QY9^8&RT@{ zLz#idAY4k3q~bGa#RzQ9<4?p-{pGA;P|D}21|rKI=r4iV2Wg8RHcJ~IEbb0 ztz8G{N0W#^b;3QI?l~DqX8qb^8do3+5N!EOdQWG!Rj$UGo&?G-nDQT zm+jj!aQAqvzn3~-{N12?rK2h5gm73iVSn!{M<~C=_=0w zUqEEW3gxIJY)g-Y;@i#gsS87@2g4Kh6p-d1b%9l=yTGwJ&7?9Pq~6#hGRlYti5RT- ze4m~LG}H~0x9ds$t z+6IDRog{d-Boa^jbVc-1PmxwdxRNfSOBVYT`lMEHyEULr-{T#fOw zyLUm-x(>KC*cBgv!pHX+Rh(I z8!&)IkmAR3Tp>r*6QrZ{x(+0$^kxNCNcTRGnn9C*6@Mc&g-j;UT^YUM7- zrN=XNupCKqt1Ms?$Un$ejfP6a*wc>#0HzTa-gX$uLL!Epq9140q1OJifU5RopW={aVJkE9xsr+tr0fVw?4lZ@!WXR(L$NblWd3yC58qZ+3t&Z zET#N6Nr5nSR$lf-HAB{Dff(Hfp%jZW=a?w2nI(iE9id3)ZW%I6e@Q;=JGyI;AAJ12 zM>iI(d}FeXrRp7IB?v*FBvK&#RP&bV`@}Ksq*D<^`)^z{P%{fy!??PI_TF>=@&vhE zpk_tcOX+<`Bw820LNW|C?&9tqtSw=VU-eBarnQ*$d}%`6N7_6aO%s@`XL!+@O#~-b zdi_SgF{=^ha;4)%*4(TBVD`735TWG)c2mpfqH<>ryotX6r`|k;bXwQ>h54aYl{jCP zkkRo}m6*E~XPgHRblzU_PldwZ+j!I&-%Bx&Dieigd5MK*NBzNr)_RZlm89teU^5$szN5 z3iLf*DOLh=k6;IZulw0a7OsB9Xn20UT57xw=y(t-Ywp-2Zmq!IY}AiKU8as+v6j;a zV3$i+vF%`fHPg^R^b!t~@bl_xPhQX0+}p4uX}sJyZ``PkF~ly27$kpV12$2oS(x=L2FiEdKV->CT0Z9<9XW0R4nkAwm4jJfQHmQR?w zLl?%)fMd}RZY{L@(~K;DzFKHsSj@jjtIg=+09=pqM>lH}yFj5UZs~F6+AiMMC6uE( zm_Gh4O32`ilRt&R0Pk3Gz;QX5Uw@ws3UF{(xVLT!>TCL*tlA*IUJq~$P`$a2XK_%T zrJ*HAAA^6mA%eq%Ojm0C1?)L1J^&-fGC4rsQ?H_0C>Wpw!40;YeqENQH{U#n53i&I zqdUM0I25q>(2Dkub5V;fBNkRV5-eS*7A8doq>aY(~wO)ld9L1)?1UG1a2@i0WZCo$qL1w+t1u6V! zoY5nBIs?VoBK%I>-~>`ucM1MWl;j2{`@i5MJM)4rfEX{wAG(QUi{Zb|eQ}yHju;D2 z*4avdmSr7%MR%!L+Y=vU?zPSg;Q|86y8pm`naJgf^_G~Vd#SK`{{@r9HE8|P&85wN zI2aH$#cQ9d0C@n999@kH|2$gi5s$Cgpt6LUx>x?hShKZ^kGZ3IL~y|A7b%Oq&>bDM z4FWRpb0yvYVqd=i6U7#UpTe0Dw7UH`Cb;=}6+(K3l8>MERp6KfMMYOpY#PMV@E_0q0E0^Q;uIBW-C{9yzHRl=I6u#6Qep* z$|o+M0G*Kq7N?Ae1i*w+2^rDMghuFP521aY4A4|h;Bc@#LID(WY82v(e&@vboMFLO zc@qRL?*s<}pDwi1(oH7c1Q~PT202%A|ERUlVP0f&DBA#LKx3%>8XzC0-m-#J7*hhN zWKIufjg5^YBEpSxi=U2Y%?xl-Bm2%@Q!Z3k_UBrL*8??73OU4Y+tlG0`F&jMIf|SN zg5L1zTh0rkM(ZLg0?7Hg0#n4v*nkOOJ7Z5hjg;J`MJeusC+Hj5dV}DTn@(Bclp3Wx z{P}MQ@+{z%4LM&-`P{9d-}sVh7u50yv<{KxB+lki7*faXgM3S(?r)HNDM7ZAgzRoI zU!!%iz6k+Fb$HJG2Jrv`ERt$xc< zzz4ttO+p+vT29EZ2x)DQ@l8JXX{DzJR&8uxsEDiYJYz;xjmqfA6*QcrHvycdSu*DY zdrvHEoog=pB${)^cU1&1{R_;_JDEC9MF`%Alp2@s0J-wiC~8+w$dom7JQ z$=J$k!cQ)%I!6Mxd*j}vb=vLo(J3E&ERrvAf!sj8BySMHHN_^O5bl;1g9uLG39bYn zLKJW4=V!HRs9zA)DhITWfi>qny`Id(CWSEe!RHHqR|jt@f)g~e>#HztL0b(!Uc&3w1^_Z#Dh(Q9Ro`RNPF^m=26+KSp>ZnC_}{y(Mmyh z!9XuA7X{&bTO|($(HF0nBiO^>$-xIFEv$*kN{2VE3s&3&?c(D5{!(mZz6=i{#zOE# z_P8&dmVa-B_-!nRzQtuXVka&j6W4l8a<%4-B;zX&8%&P^`&#UOMQLY8eYSthq83G! zY;$b5>k~pVRd4VnIYms48lt|_sh`Isr;joDMr$umKlxxW6$`;;+zu_cwc#EY%!c&E zB5X#z9}J%5^4nvxKgJ7d?F~$YioD@8|F=xQ{V`p#Mld%r*`4x*FRFhl=CN`+LS{84f&r_S*7{XPr#+akgA74jud@9|F8doQX39s0pGnLM|YW>F*BDw zaL8{61rEBB`&1x2nSS*Jxsyg`mG9Z1zpdvSU+En4txAIduiZQq%Gwc z-XYlZecX8Z$=JN0*sNi(B2t^$`Im8@{Ey6RUkbS|JHu$&UqmjvMq%17biIiobCaTy znx^q9lcHk%G1ZwZ9hbvd;xYV#fuo0AC%72y@O0td2lfw1ZJj(btKDxVpjhxI+Nff|J3x9u9Ps`B^Y>PE`5PvTMu!~QjY)h35^);A^l-+XO zV(OF{xWCg?pPvlguW1Uey*uBso(`k6> zEaf1B#9PR9U~J9^pZmAaaPW@lUwjHm>aBo$Sws8_qc*IYIHl8sP(5kvuZCFfE1G1) z`^mx+r2BY*K?;P2Rh~})n5DSdg8yZ`mVmj!mV~0LD@BoFGPNgV<80WeVD(mSTG3zhY|+^=pI=zyHB`gU`r(+ z+z}l{y2mp5E0`Rg4X)Z1xK4PkN~ZkTARSZv{N198uL<|!%Ch=yF>dT&PN!LV->=Se z@T@sv2$`p_kE9^=MZ%#fKVXbu-~fo`a8E&S zAM5AQCWhAlp@DP8$I_lKcMMz?F-DaNEUIunV=813MOSH8)^~8MOo83jS?~!`RgnB< zW#2XmzazD>%7{BuK;pOp-Q)eX;I}RJEf)3!{miwFF>=MaX`+ieencwfZ z)4RVlaiY;C&n0&wM#enxL^5q!Cthb8WSGGi- zx|k}8gd-22v;DO2z4K>3$gh;_zY`X)6DLL!U72ztPU8w#BV2aUR3(pZc>F=R5gk+$G;`+!PFoZXCBA>!I~djybrwFY_Ga)_Po==p#-PB zZKyJX^pnrPy^dv2tM7eab9hrQCW|ZDU`{Wfq?5tyz|Yrv=|XDELF5m2z%4ep5-r-u z>^r&DRbDu4R=8FY_-FfeAV}Z=d*;GDUGM%>^Kn6nEomAy1jd|un9RO9e@LwnfB)@E z>c(XcT=Qr+#XO7~et^trkK|QUpe}uHMBt#`W9|8U0iEq!NEWb1kcHyE>Q;5YCQ3%} zB&x7d)qD8uzqhSB_;#Ok`k8pvUm4Sm_V~p%?foKfDf7a|I?K2^6#BtT#Kxju3(!gW zwNC3j{j->M>R3c9aEjr1%$h!bU-Q0v>vcw0L#o(_hz%xUH1;C|OxWF5!wCO){`+Kz zy0?p-0j0zmV-hRc=_q=?+ zRdT*Zyvft-pNfq46IdMJ7NJX)&TjTj5SfX@vF*~W&&JN(-dr>Z%B|I3@CsIH{9w+s z1Nq*kmD5O+?oq~r#l86T_aUs-3Y50^W9#)7EU{R%QxHYn2OP}w^k=8;OZ^VF_3j?} zQT$?x$g!A)?%CC9Ix z`sd!(AI^P9B2a*Tg)_e|&bMX28{|1&LA`ISheh!b1sKT?2a-k^UFM`!7R6Ft24fra zj-hB1KV%wlFnhq`XzK+`zsT)XCk-PTEa?Yl3QbfM4JEn6h0`@~m6ATaFlAg$`zCRQG;*-A;``dF~#vAZw1-U4d^giB51McjRF4IuxXb;Fu z^!j_na-B=_`mKC_hTZo|8J0(#T70~ME@W)uxpybpx~x}HQ?8Vl$QAU9Igt3%Ux}Y* z>V*8m>1_E{VhWkoXkeq|KI+bl=csjS7j){;JJq(^_u2tpAfL~*M@T;Aa!Bdm;lIK9 z`SIqc8)e1-Py+kj<1LTzh^EL1h7ITfFnW~`p$-66_Hzg75LB`h*$@mide=Vlqw}AH zXt=?Y6|Z(>fyLSDUuLRR8&b3HcAuJIStt<_j|F8w_A`bwrj2~%zigGj|g$a*j&4*QQyy7e40XW5^pv*Pd|T4dxruZQs2Wh9=WI5Z)r0PpA9Dp zGIdV-$)FPWtHuWEpxdo`6<^(~>2Hpt{G;GramxM#n6G$r88*lm*ZQm1Q6hy~=I>{| zN*E2yKFwdbp!0R!yR{C9>_vhn;s#BC6;91KU-<|j-CBtaRFxf=UwJFcPYBLL#0pOF z0|h*werZDX4eX~91NDmmU<3qXLjO9T$_RG^K_0snEh=A|0UPrBqJ0YyiBVJdqrY+l zcZrG@Y@t>_cfzsdBjY8w1vXl3|N50l9^w%tusyi58o-dT6{P+j)uTTt>y6!`0Ow2Z zshbpR%O^qLcTAjGGnYRy!atbX@F=4n&=WdVGr-Ge_{Q zMr%~aD202?;uzo$8v%Y<2rHRLK#)ie{oFs`@U$ekPt*Z`P%nVkFf4pT{)$}7XE4ZM zz@~lC*ZBSvFhh!&%LwPDnejd>&+?bUz|#rg?E~(YoW0lU#CElC-fC^mP>pS3fJwJY zsD1dWZzFSBfN_PM@MKT#O9@d*Q5ZFh!A|sL!p!K~*d~J254eL`m5-|VJ)JCUu7m65 zd+pP*d^Y2d{Gwv7x@a3BSWedS7_x(!Uzx*1Bonz&C4f0DFh=U}Fs=l{4zUa^ih~*H zs(^%)_rUl|BIaqqvZbEmyh%7o4@ii7ag8UQ7noIRF#1ZdT#y)AmlVBC(UPU?X=*Bzy zgOuu85hXztuLhv44=Z8r#WF9c0ZXWnAy)aZ12SEA=_rb2Pzn6rJPHe*EEc~9So}Ms zy*C1S9^SaGvJbq1`@?+|7?$gHZrg(humk)ITh%puR)LzaqtVZ*V>k_@=aKq_>%(c z>)xm=RLE$E^Q5jxfM_6m@!22lD{;Vz26uh_GReZ*p#n8vp)aiFVsB)5m8Kh%7~sK|cv38+ZFkmtfBfb3vp z-6~(>+z8EP->_a@P+{Vgm0>&vjyf?kb+sTO-4cwI83d!e`>1z>{!~SPcf#i(vWw_E zM<&r71Pka1G6FS*J}+Jy#r&hcU(zLmGZ-F-0}Bw=cGkw~$Q@pN^rETKT&=W~y!nC8 zhff^J(=fobx1uzJ*?<5z8s|jf(Rltqeym~(#P$j>08Hk0j&>0*cCu!XXEFTyJ?%rZ zG|uP(XhYLeTc^D`PNg3b9(`741-qaPjouMxUl}cIT6|uPvI987wZLI1NUrjzPekP* z2HebRqBk$jZi5Wr3bJQs7lK-@6(=K~4{nlD4BS3_l_KeVZ5T0wEX*|O;@V@aU0yr3 zoW9a)j|g{~G<$SX?Fx6)Y(i=;32D43KCR6nZ9)mk~c(c6V9KHI zJj&x(ff6OZ&FNmO&e{w@km!Y(D;b#eB-r5Nc;g6_#RdxjiXADsmwDhDKmdN8bXk~k z&lUvY?&X7zYqI6#zM{i6WZ{mF?#>J zmuSi06>OFMI1m}tjSB#zbs3H)#BF9sVzvJHT0?(-dN>(IFF5`T{wsoP$7}8)je@|e zb(YZkvLkP#Nx>9&kN)-m@Gte8AioA;NbyrL+!ro%?wkFN98Ro=X`EnU{>Qh53Ywn) zM+4{Xyw~WyAL6V@^V|>36I{B0jI8}c%NP?`LV*}Qsoq}@lXVFCR^)!)MR=7KCP@Tu z*~FJ#S^)8)Ci>3-@W$}A*OU!&fzgMdoSF=reRQ?(<_3sJ6l`Y`%uyoeXB4o}^H*yr zD(g6G=r$!N-oV^BHp?R~r6m1Ct4fL+_|$(SrzRj)4nZ00sS%6F4sKo2;HLI$KN8W( z81MO=6t>Fru6zuS9E2HG9MGVb+df~>kzjJ5g89Xxpc>{m{N65u4xWBa_4vl1B#W?w z)(-%b1Wn72hRfyKkwmxB(ZiQ~ifr3Mr*__;0c~Gn7$xO>nbFU|?2Ga|h(5C=w|NE2 znIf+P$gT8N*PG=a&DN=-HSA!;UZsa$Yv9;vYcdDOSJ?>6V2sl9FBfZr+BjO=>GR_Z zZf?YDxk_w9o@|9LaG8@YE0FY3bXntXA-^xw*`Xie!)D&u`8`t-#)X*tBuO@LBYk7U zrpyy%Jpsc1(gFMh#uEW_bN2|SpY(ook9Q2^K}gYG3#BkE)O}fCS>4G71V{kgv|r9< zbjJyoDX8#R_BswA#H2ca6bCf>S@Ss=_nC~|M#ELWTS1dEmhAxq%U(Kzc76B39Y7?h zbD`pbI&%lt@#MvtCJ?L048p??y1Q%&A^Vg~O$ju2u2 z$n=*9@@7-l{cG)Vp0;zRW*Ahat75-55{V?)FV?zTCE@O4VHQg8!}AI3Za(7q+`|WG zJ(TE&o)>&b81X!x14=01KqJE=Pw%WevX?Nra|&T5&S-M7cYGk>rwwU;vfsXnJi55# zZKZ5x$QCGj_ET34B^oQUo$LyON@Z-7e4U5->mHA<59cR4 zc)4JGQG`PU@G+B-Us=9{wh7n&w+k46QXkHmYbh1qSH*p_i?!W_pK}?l0klwPchY=` zdcxLXD$rSiEmV(%!~n@>kkTl`8#aznxBA`sW#0^>u|GA#?OGvEaeAlxAiua+&D*>y z29WLqEx}0HN<8~LSfg6&D~&5lL0IuXRO{7L%KI$U3?8Q7NZh_&787YCXsR`B$*4=~ z_8kJg5(2y*F9Y|i%!MXlIHSMDS?nd);m`p~`#@O3A#z^CYTeMUhT zvcwG_I* zYg9YsBh>{aEh)ddqlfZp<42Vi6Jv2wkmj9de6&q_u$MUt8Vq zw#Rde9fz+n3#?g?9QHvmptU(IXFsT3@6kgR5JF*%uT7XJAV=!Q7p@oKDGrTys4Ev^ z9Aq(5`|0P@Ilf+S^P^&;2fn4TfuCIZ0xH?P=6=KzrL~R8#3_KQ!G0_CabQ+VQo~fQO z_&99#g(f*f4g8-?IPFWdFOjIh6cf&>0HRN2=^Zy@I-Vr-8}t?Y8}!wXD`9X1pG>lX zfT&_o(d`8nlh{dML?*ba$?;#_izuekMwL5(w^PlhvjC+nu@*=wO`$T*7fPWS)GhqU zu>zn8=+mqg8?Qff*zw?KiX5T!kQ8P2IO@XG^UIZ*j^I*Xe%DpZ-)k5iUgranM`@|H zs@0mI)_@_Qoy$?6^!V^r98yLf5&{?qD$>CzF&h9F~a}S zOe6wW^%Q$D50G(SmRukvQvL23zs0QvwMgr|ZZ)SnJ~+maztmvlQnBP@UwX4|-;@Oh zV=&;EbU#o)4Fa$3H40SdIbvH2w6WJ@9f8cX0UokMpaqCwL4z6Z^BUf2bFy>ghEKZ# z=DhDRkhB&-BELKe7u^SQ8Rf>B}^^`~BP#C~XPLuSyL8 zeCV!?jz$LzYVup49GOPgbKds)Ti9odih>PJD+6XmfKSIsyk6OFM74VY;I44ThxClB=51cI4LFQ4xf`*qCIf z3z$m+*O=0>UV(dH~$vKD2CkH#g z&UXp>?SxwmVfJey5zLScE9R3w3;b?Au&fR zq^gwxcz>xMLoc*>mQ+5@PP{_j3n5CEd6+Mo4NaKiL|;I5alMk4G5?EpXFPqwV~b=Q$Z(>5|$Lb5%%t|iXq zC+Nq-drQ7l#b1NL(|aaoEn`DzTsYxG?Du(xIPQ3P2b1oJOg{1Pns%5d02#VL3`& zlOlUo2!xNXKEAyIy%_`PV2T(wleXsW3Z3Vpx}wc+1xxnlm!~4{q>5^fDp>2)Cs{$` zwx9#P$mdFx{JWm28CCDx@qU+$K@EL0A=y>DlvhW_B;$bfrRkmXF=$Q>YP;`3Rm@Y8 zhF1oCZ(z%TOufnquW9)NBp91k4Asuky*IPbPYs(FZ^%CeeoN>;Hv{pNhbti6GtQtQ zRmQjxcO3LuY;C8d0NNSN&QIIGnF`12+=&hX%`a3xerL5WEi?5&duJH7dS<7Y%MtJm zGGE~-@c`VeIuu(t945*ie>E=Z0dK%?(62XWHUkFFZ{N`-^nzH5%U4rXhGdpI3Na%z z)oU<{*9Y2Oi22rO-pK8r`l)58-~K=nw$(nUxgs++VUFSJ3&^o}3$;G@#fT?TqQBV4 z$DBlU*zB|Ti5mkChO9m`?IeDPcouEnKmF<#dYLNY)Op-GBy+^a4SLVl8g4GcXt}^aUCuDdH#mR46X3dgI>$i4 zKE=k1`1!Cx@(*YTcmN0*#+PUU=PCxsUobqEj$QIyci$Z7X((|AdPCv$=2XNjxx8ec z6y&gslW$-gta+x%cfKhf+su$;&~07dO(sJ~Gm84>3cg@}@!iviyi-Zmd$bMBi^15@qdeqf^zVGkX=u10*{Cs~Rdg$~4B z?TqN2v>=TP%$~#WFG!Yj7H}xwaKr5`$7G%XzULPdWn&5mVAm|q5Bs-duKuTE)Ftv6 z7bkys_4Me&57Yw#L_QX!O`neSD~=T48^0-1`gZETD2;ytn5+1xwr4tCiN~l#kjume zgB{Wmx)!}lSOml$pc$PQQHW_({=9JhPX>5d^t^*ugyxR2hfav?X`T0Hc113Upy2Ko z&^xPGy+7>NokA)`zJD!3G zAdS_@zs|j@kn)YE>_O|2J^EsB!`?ktk(;r>t4+{br|Cz9BP_-kf!(Ph5Fxwi!EI}% z*+MC3=wp#r>ouaG({A2G&+ruRHG{SpTsqv2t_zK#p)PhY6+oL9=tT(6!nZqAbTTv( zQgIW7#{qo8v%nJx(B+RqmUZB~!rev?n?^u3s3M3D4Tb;SF^+tEkD%GV@v&-nb#+xvT; zS!Eq{`67z*6UO?)Q?w#_dm-ok`~=)d0^Ai2rcD3A*-2h$6oNtPqjF5#I|NY{m7!{p zy3ZWfYwhuLgY-?qUvfMC{Pksp=ejp-jRlFUu+EMNS|hb2?maRDGSK%-_~!1W6)NOw zxauO_1BimWl5MU8hb)m&3knX+15xe5d)I<3uE!I(H0DxU-YZaM+!=NG!->}ZCA-~O zU#kNCc17#tk^oj1G)ewp^?8CoRx#|ixsAzYQgPfe$fjIEoSgoRHsM?UqEkWFVMjX2$y=UpEsrn63DP+)sne0UMsx&ki=kh$p_x)B<|ZFsGpdn}`;t9q^7)Gj(NG zKJ$kdkhoDDsIOskJ&~c?qHPm=X29M7a_ilOI7c7%Y#^%_r1qB%ddp;Y7%V2h^8r-< zeSY3BC7U>PhB?e=al7iry3FI!!Q$5Yo3cdrRv(g^=%?Pm%$Y-$wlDs zWmPEnV2v2Bc41=j@=HuLXnXVrp!_t@w9F0k{8PaTLgOPI+CEpK{Nl3ey&R%zAczVW zAGnnfFyzH;IwFh9XzP!ppC#-x+y@6u%`6QJZ0Q~H%OUa24IIX}m(gbTszZ8B5L#HT z3z{|@M%wTu_mOQ@g(*O^z56J}O~qmfAZ|z?h|X-|_-KN^y7)OjL+Zui85nG0{|-L% z!>wr#G$alHfT{;Q0y*J8<_y>wcj!Ce)Z>|vlMII+thD>`8CwRho&1|ErHTW}BFP6d z9T$<7E$vnoj6Wc8V&9K_;L>R)N650aZ72@Vs4+zDo-9zm-H%<9Emm8huVh>6W@3X8 zR&Oz>&oDDji?A110AK3kSUpT3gq(L=Q1FA_3<)-sP(8UX)ahlP(Z5h%Q7r@Ni!}O@ zMwBXG>$m$e`s|{;xh%j}h{p7Ly|3PPMugNo-wt>5Ii;^j!_fvUVm(mfJ$Ire<^~3^ z%%GPT40{18KfE^dg_0jy8nVfoVvT91hPq15;z3r>`=k?d9hbl{80r!5eJA!oft486 zC_eSbp??_|od!?n2c@PPkJ-+2%N|7`%dG9llQGqjfuis^dmf&mAx&@iRc zL}#kS;qTlpfQ+~ScBPN%kt_z*3&vw|o4l7Gz85d!@i}m5r-EyDhL+1J^g|+413ibN z2UHo6srHB%8jh9o!~XzCf_|dT+dtB|Umg54BJQZesYZ>C!) zs-#FZ(UAHTQfNVFP$5-47DfYz%Bx}6Gfg-S1C}=m#Gf;;HVQT_MAXfj2W+oXbj=rF zZap|fQ*c@P!BWZ+*0brzpsI=JwJ$a^ySHxk~K<@v1 zRnY7{p>c4sSY-3c8i$5!7a(-rXdth8^h9B|UNui^Hhek;F3dKAA0l6Rj6&!pE`@IC z$FF6d`;KVk+(9Gq!~_~nuo%94T!7X)f$Q#WE&}ls>R9e+Iza{!k+JFc4?NfC>uEjM zQA$un2Th@9-*LJyhrFdQOU9{(^@x)dI9~+oNeNV|aK9Hlj&wdN8_jR;$tr$_ zD@`V>+M?LPJ7Pc1WNwMf15#11G5wm%&@!JZ>2Q^S1z<-Znei!p7bUtxr z?Pr48tGi13^c3jeH>@5!Idwacd0G{LO5$!2p&~cwt7z2+5kU49xU4Pot`T&tk})Oa zB=E=+8af1K>^iquRE7z%cM!8nTACTGMSqs(jB*sl#c27J0szwGaPKLBCSlwJ-O>E?o&)ao zWWx$p2pds;O#Xepkk7qAhPHGM5ajQKf9Hb2oJ!JKs-wF6@)fvc@{(KW{f3T_8-6aLitu z6@z#~=+P8CI(ayHP)q9djy-97`8W8>#?Xlr-m3WV8M6MP(Qj_^!@GZjztSo}V>kO3 z_>1lUL{yn?fv%y(#j$@Ww7aDa*avU$7r2)J{MGym{PmHlNQTOmDBR45d!E4cXnXSW zetg3SZ$O^|w;i8-g=TS(pan#q50U5n2>5CSd;(4xQ!B?wUQ;}w(3c9)$;)8q z9`TsZqjxFEDSox7*UAqk0y>Y8d^N zckwFdv*G?iR5tlFk0uF-1jbAQ#16N;{BlHcs=qbCOv3x-74jRr*1(no=v6Oh1^DECu`(|q-&?pAD;+dZ7|B$bQdqkZCLQJ-m|toh zLEk}ZaN!_VHM=dvH=$Q zXXEnF#KR~(oIAIbe$^bXf(z_+L5&CzyPyr7_f03-;AHZ?grW8?1Lpbty~n-VKDRk~ zQmb(1nnfRy7Sm)X{u>Hp*n@@sfBEaBKU`|VFqn|}a@8Xu&56FRW$Bw5R!*h{HykME z`!T&CZ2YEwkPFr5O@ZgrqY<>&C%tQss7)`ZNRNR0B47#)- zcxC;W#*o~iK)>~v>vp;4>=0HHtFLr~As&}!0NxsGJRXif7rN4qd z_*cP0rv*Ip_61t*AUVhkl>U8TPJHk{2au6wJvM2zSjSt+$mNzuZn=AM?@(!>)z`xc zFb2EVWcdRI^7w)d>)V!n8{T@^->|Jnmh|5dW^&l*v+`;SO_o?d9Zr?~nVZ8;Off*8 z`9NlHpz+fC#AgK$t}KE!f`;`?R6PMk_Ek!#&U^1LxMUQj?R#ONzH&~2=uBRsi;VeF z0bv-#ak2r$%f1tyeftie8%hKculMh{)$%KqFNMJ)GRC*DG!s~``2Mx1KqFg7VTf33 zI8QfEICY~K!6+~pbQVGLnV$psWUR2|A=2a(H%dNvRA%3^Bv~-(Xd(&lwLT8)5zT55 z1HcdpOSiQW7zw!3==)PIynXcLWtj#SKmG4G%x>qCqeQ%+@4Hwqa81CnY6+Je0gFq7 z(sNjOT;Pi^P4iH2;f#cLRq=Rgh!RX=rw}lYikIxV5~IW1rF@a?fZnEWyXDj(LOpVH zQX5Hm=mCy;CG&kdoFh#G%of9)6&VVDver}(Bk74jrrozx=dHMU_k*Az1;5bOsiDCk zY6}KXt&k0^74AW4++agrGPz5=OL$>y^S}qdBel>Lst?}BP(`PUhv>F}XTJIbA^%du zC5D%yPIzmtDKvuLdq$zFfqiRA`KmnXLvHU35fv!PlnF z01A9hlvr&7L#H%-dqIU!4&NLagv(cq@}HLrlLEEcJUjgqw1CEm0-(oxKZ^-Gcfr92 z&_l9Rtw{u$z?i)o8(iWagWv%w1;npzg>{Y}mEh#?RCF)s^$GZM z(lsXDRc7X+4XiR7P+LKfeqmts%G8I`HVOHr0Am5_Rd@(IjmihS5E-$jx)K|yTk)C^ zeGufnK<-z$=f7*D#$9GYkITNU0Zxqa)KM@GDAQscse!gE2Zf)#hW70KuzwuuQ8$&jSzW@M+-2ku;0Kg*utfvf3u9Gg+Kz|=6jwZL@3s@YUM(&Hc&)S23kmHMbQUbuN7u`WiIjt_vOkO6C zf`fc@f=>|)iqttgdKaZYl3+vhkTKA44uk$qudjzh?wuRRj=5f;?YGN1ALxNrK)0wQ zCN^s2Yhi@W+fu-;-_QBAy3lL8Y2oHpAYfC%v(_2Cy%RJN1E9>?13!cNYW#jSste*{JBYsHtAx4GpCHO3!DDF1&!#P&d;A-= zUr{~p4LFPU3)EtPf~#(&#u0f|-?LC%^lf+2!-byioo`xtPOWEQB&0^4_0unk5g37S zv&mkhEyl!#dM%mSeb)#)$FIHE+o&3$yj%{26*RxTr!^{hwBo=#ns?=a83Y-i4}xW- zh8jpvZ)ZP>NsadFtAw6p#1^EP4ehpSQJnQkCF#21r?Ww*vk_b zfjkhK?yO^%b&J`^0OBIzUc3lSnDmnO=zwzRtl@@ zPt`^DqJ(dGhQDNJkVV&f^@A=+wr;lYypYWliZ3GfRs+kOxYE|otWDK=7K!73oEJMvDpMK7Jj)>m7L*!`0DXnDtl4c#b0jQb)EI*Mg_H<@aY2)Oo~n$fD4iIJy z`4RexK7}bpYQgwW)WC$n58Wd0yYd=A9$n9L^8HD~lgc+PlkDO*-1`}z0fzlMwOStk zyeFx_K+AOy7s?3A*E_TXdYXzKpwmn^^n3+BE$E`?^$3fW^6eju-?P^)3s-6hcPcSi z+wAjrdVxYWuB^6AcF@D=C%@OT+)=Z0xa$(D2K-^zbIW_~ zfxz}!>0P(v?qUR$6NN>PP9er4i{5hTWB;5s5#H_|)2QMPtABS~sChW9>t||-3AZ6p8jqc-l=#FyHuy5eEPQbX1!(p9uy#wFlaty!F(vg>S zbm4$Ho38wT&C-Jm--G{?p39yDyWk& zug(%_HKd+%_Yo!;W&j8uo)}6-M|)QKowBj_92VG^Sx}=Nc%w@xT9BzWyL|j5D2*nR zm%ypE0uk>gdtC@)1_(6m^ub0Ig+Fh9r)n`izH;}Sz*-}y{3X9akXQpPq*UImyF>{m zNaz4H0LzDUNu+&cNx!}L-rH)>eAS`$DIQ;c1X%UnDF7rrjONl2C1|?pk_~=u)6$4o zp);R#$@7quP`ieAlIwnzxHyo&&Z=1n@Fc3w1-1!bq)Ui892&Wk-SPa!_p%R9-1%S` zW^^JkAQ_m`<~|6{g^51x$F?Hdp{*Y{zZL5N&15n519@zsinDc4 zHL~V#zUMV)$%#?azJG@{XV}l@ETF~no0}Mb6W2W~B_R3w9#L{%#VUW$Z)y3sycp+T z2XJ_ZOfC(O#%WdTr(wwT&LL&c7EcU0#h}qj_R<` zci0JE0a(Lg;TyMIyo1Evt3_zU{Cz#1N-?|GgBwh>yVt`_+iT;Gx)pra{i#CDZkIEt zT=~YY;l}VILl4gYR58*BD8v{Q?bMuKSQlC~#@sCl@-#{zqsyB#NeMbwqxP0EyToPd zXAF)@m2xu(w_Va90E}3RpZDSb@*0PB-{j;h(0?pjkpzIbTQnOE23>#*Q?Vn%zZYkp z7{7<)JW;iKP8fl>2 zPKzi#X-EnU>;rNpZ(7hF^FBWMMbYy&v{AkzN3a0Wo&)E20I4T&&_{yF zU`R%bPd+p{5vU7xy`1j?;+7fcTQ3?NK_O-h2EQKt_kHxj&jtBFG8GV=hh{TL)07`4 zo(}zVb&x=kext2@)2{~j3U%??v45`oz3}rB75E6i`TcIO%rEjn>iO7DT_WgZq0uv8t@lupx#KC1^ko{|OhHG&cNz$Zwg=QTvVy z$0E9?BfNNRpdWk_T}Q4PRPVJIn3)f6sX$WcF>`5g-Gn}HI1v1LFNo0`jqW}4q2I-K zMnlAEQ66}k4ENJ3_Ujh;r*nyc zd56uo!@XmGi9Q|(G_lo6e#6)j0;)HS$XR1zcVuXm;HA^SxoKM4Ucn7_=I>&w`!iDT zqkpdeIQ;TMMb)}*g@!=zyv8+cHOB0{e5 z6|8z_%-<`Am3B0m^VR&kF1F!Z2~3zE2FJ_@b0ug!`J)yEURER#^xogm=TV`*HOVZw-HTqdAjdrGmk~Lk=3;cDSqqt(% zHsbE#uH0N(5!$HH4;JBh>kG%`UTpjGyn`adxCa%EMBCP}ERS6O{MC=Ps(}~2S1XUg z*%irPG=ltR<3pKBGg_M>?ar*;75pT*-}ub^>3CrSe7|>_eMU@@5>NO!KJW7p+Vm39 zF`{l#bN@cjzx%U5?;%jN0ZHp)F-2)XsJ?En3EQ2=JNnhBO(87Y8PZd@5W@fyJCK6F zf2Qs*_x9vIXXSXmYy5XVtC5_iP|Ww+ih#}2v)&1Bj*r-l`g)t2z>+T#*J!$3`@Yx@ zJ=HiFL5l}`qv38H9U=HWn{bUG2E((@N{!w<6Z~zyH`?ej7HXEnG0@Y5!zsHDqy<7e z0*(_DD)|Wl0q9H? z;;ZnNK&lBkG>^A3nK|RYV+--c8Oyxf?;VackKY&3n^<~p2JE*2w;~cDaj!b<6TVvR z>{(EAMtU#_^LrwFN&+|FJlfApp8rAETYyKAZEM32f_tz5LWnehpzVUD-Q62)clSnu zL$C;%;3T-)3^F(a3GNygB>3PHT>e#@bH96rd%y30o+O=gx@uSL+H38l?;EoL1|O3y z@My7St${^$B=7)bjddp=OG_aHA;Grm> zA1p)^BWe#3Hu%yw+(0scEYpA=>iS*Eu-rhTGZGl1fnu~0BVhA*fM$tmpqhj(5d!$g zaz+sdLwLf_lxL@MTudT2gcB+C*a$xAibL9xtI)v;q|vAlsigomo4_= zA`Y?L4TOG#D4$s7{Sf|iS<3O-xGwK8}( zkt3psMWhI$3QGh_oFxvhMKCK&HI?RK3xsU4SZRg&TRP1JLj|dNK35PjihM4ikYK|Q z5iQK8lNfv{2exDfkrT23+k>9KSDRxo;0d=zA%v~><7|MS<8ZSz1fm&`J^YX>rhCk2 zq6F%CmC(${SIG=QJ>TyQYivTF+|Gb03K+Q9BPm%Lm#Ows zO>{Fu;)eoqp+rZ4Tt87^Nzk029awCqRE!ro*fs#O#=E5uJlDfPz=Eh3BgCjQ4lc-) zxbO~@fg7aYfHYNYq#?^m1>ah!mqABRBw1)Mt;lg+2%_u+DVt^f0ci+`H1HuW3k#${ zV6*8+7!H)V0U4;oBEm$lT8WqM!FXd-9ORZ+GN5$Pfu49#ngeT(kb|HmF4OyKYnMgnmSp9O~ zZh|I_2vY_WVj&}&2hg_;p_WbLDS_7vHcYP70Y%rAke-KTg~b}DQyF(F%_6Y}A5w6* zvap&Q;Yxt@!z+&<#tustCWHy9C{z&2Vy<9B$}&Tfu@fI6#_UcTUCBp+R4g}$f>B@; zE1{)Z$cDBZJlPdNHhYUWibs@>$s#~>sg^7W!V+PzxsXRPhHYv}Ai>46aXvK^-gxm6 zk{MCGV4K2cZDNvE12I*bD#7|u!(nrh(9n7wh?}ss2*(FR$W%i>;-q^SVltbkQmMsw zvB!mGh0JIY*JM#cU$B+uQL4b;6gU7COY3)&Nz#zOO9@iUIvY_!U@(aSI#U(pxao$V zMn{uDi20SSi83+ezXEg_9~9YpByi8B*)EJT0kOofF+ zcSM6q0GSa14}sSoF(@%uJ~3#ti(OPT8mhjzSb-`o@^S$q*{Y0dAtY+n3i+HkFrWil zDU3#BanQ7gO36?vV`PfdU{^`?c7r8om5bF_Ei!9#IoZj@dd)&A1oVJ<$eW z*#agBjblavYN7$SMi8B3!sxA3K3{CH;#ILw(12(aPsps7aI}6}7=%9|aJnG~5Eqg3 z26|Ac!vVOj8AEgnonkXkGr?@Ita6}qVq17#x=$M50KJv)hxG>kp_%Yj4Ur@SV-CRD zcv=t1&y>sgHjA1Nb7`$sH;~=o{4^6b1~CyH2?l2&rj8AEa0exU)pGC*API(p4ORhA zBe_gGh6-Sx=>eiBAu$kjOkn1Qwh=@R#bgEw&tbPHRZ$m7C*%n%Q8XQ3+f^nuO%U|R z#bGZ&3v=Q3sCX<3R$fh!Q17N`qVQ#g>e@)OCBWpJ73uqQK^P^jy3L$ZvHkJE!Bj{z`K z`CdmMl%r!aU4%j1HJs)kw>YdP|>oE(^QK)0nW8*FrvT2b5Sh7?HSf_EcpJzgf zADNJz5%cAEofqh4)Jh1T!`h?qBshCQsF%C#B#U2;bEu&S*BwG6h$yqr{Z1+tSX$yr zV7&J!j9P&pAc`o=I<=gmq6Fh%vKh@YDitBG#2F|1;(WZrASA$9JpwUL?U!Kjq(q1j z5xW!u4GFJO2TX3GQ;&m^KDR;PM?gD)kIaPF#0hm+=w@^IW;QOwih#V)0jB}V*?>qk z0&@<=fJ%yqkO5W*dST*rSB&H!#lVPRML3WLVG$r5OLNGj&^%-zo1Jo*RtHEAKZo){CZ26Cz<5s9W#pj9FY8;giM zf*=aS;{bO6Ln<7=kN|&sJRArMv5^Zm6Wlne1)0AHKP2^PbUvd4Dpf%pD+7EFIS}Hr zH~`?QQjt7iqZm@RUb@K-z-?h3azY^osFBzKj9)H;X<$hs0<^(SL_{D0_x16wM(|Rog!#9tXD||ic!UDj6LL}XRHG9J zBVr~yP?I<$fB_rwaeyoqaq<9n+K2_rdb$*_KBT0$Oi9Hm+*&y|8m3WnxCl{fB}r{0 zYTP35388br9uJbiKc}h%Vh>djHBi|!28M{JVYSee(1f`R4OHJmZSF`2V$ci~St^Lf z{Q)Cze!GJzx=|~mt1OtP-7VH8q^^*GYn5AQ0NdrIIKn=SMyg8iXd0u!E8+?wXp)DA zls0%Ff2KvWIUXtSqUrhgpc@x65p;lw>eN6%lGSD-2V@o~^rstnF{Fo#71G4@Uak$J z2{9v5LzE21;Ymg^^x9aEGZCQM9se%{MU#WYUAKNKAFwMCfD7?*~ZEA4RwI1_;QB4Oj{ zKw*j%!kr|%1Upo2=z@B(3V6#LSc1rI_tQdgIRUF7v4Jpz9wliRVFpbXp@qpbG)94C z$OKl2+F-C5WngUwaL^0Jl~{rbc8Dq$GN9x|4*kI~s1@SU@g^zNq=2oH4v|k9TFk?^ z#cYbqBj!3uaxw#`>@mO@!v_*5rkbuJ5KYn;ji;qcF_8H;W3|x`EffQ&WVlcb4%(Qo z@Jkf1#AITYKnlQ6THrJb$&?--EsQdJra&C3bO3LI4~Z_CNrUK2mWRQHQVw`vk^E<0z-`UdeF=Oogxr9g?O$H z7QLJ=2_l;;BSeexLmZh)4KNFAwuA41;!z+Ffp8-pEiz)ENHSnl&=D;ur3GS2A|=KK zI1(Z~B-HAmYt@N!dhm1$&t#*SWf2m1WMEFy%pnG#aoB(Kl5l)PoE%NkyDVW6bbWZN z6rRpz;!|iChC^qC^h#6)4GKQUCP*{^9nA=kAqjQ@mafaE4jYv|oxz6%@lLpzFkxtl z63eCo<&lyc;~G>3pCQhc0ZUp?>|q0kR}31Dktawb#57ixo=XlBp-N6oFq_2QI6V}% zK@}WYO#-0HsM^m`6X<}g0dL}j7#>S1jv>KDS^{!#Vy)5V_A;m;flmWe>1;gT?U4nw z7@b2NW8oBWrhsgMf*PE}76xVIqQ<=d@(6yFlN}5wSW2%ZY<8fX79zJUINc=xKnWPn7htIH4x@%iiD<)0y%b|q`y*N|LGADW`4mYa(y+x5 z3y3qGPjXSw48Im`kbrS1XliQ$X{DeA<5-T1>jFR891$ksHlkD*g%8m{Jk_S4nhqri z9HTm+h(|?nF;MC%3^oB8W6nq>bGope14^%IU>J|&Uak7>U z2rXQpia8nq@F_&y|~z#3NZX+apAfQ3Rzen}K=ME6jCgTO2Q|Ux;DO|tCZr(#5Og!x&`NE@s!%#u_z>OU z5=uuio+0y@Nv6Jj{Km?94bfpE$|6iTgO7EO?didas+fh`2wF_y^c zLA*OL6DSWKvxE#Z`IFc;{ry5ld2@TTm&!|I8J3$ zp@TC*^}azMF{xEDj-JhQhJ~<}XbPq`N(}BwBAT(>ec%xsZ#84^nu$~M3VR|EUCaQsg9IRu6O)B7qmOWqx zhTyEp4{>A$TNsG&*hE$sAW7WF3h)}WM2G?dLMIox`ITOa9)Qo|emT`5RVx@An?r5G z2UHd=4r+!aUUC@62(UzsIM}}|vsZ5+XiZ{947hB$Y#UAjPo2ip1Slrt7gxyS33!7R zHh_1N@E$u+r8hZ%_>;}HNf~|uAi}62(nlkCsX-Pr{~IJ?ubvukNW3IGg~L?@6b!2j zudp$V44(*Xq{(1JY%F0G*bN3(GzP5{Vud*pj5#r+pqK~{*enm9j~K>0ywxqHm^lV% zl)?6L2@1T!5M(eP|&9#t&yC^Z_Lzz?DZ;>VHz#~mA@ z9TEXBM5)z$1)33Y0$G?!6Xb^MKCPJIBiIFIE;$YaB^u;0#m!C=8W@Iz6gET6w-^{) zvBM1pgutM(h3uk;SmHO(eNj1sPXUTpicl!F!s1hSq#9te5ZNLsvWf^PsxS;5j|a4f ztq5U8_(`KD0vL&eYu5!m2@eD$XzEDVCzLtjA}n8JN>D@$v?Z#91ApWSBpQiVX4e^H z>=3eB8gOopM@fQA8x7z)wMYh5bUp+L|DXgpx=c$^dh z*5m>J53(gpB#ToRHj%&9r7AAfV0feG09#RnS%C4P2d+e0Ph|Svr9BI zBA?;XTVzpk3@b51H@yg}p~C}VK@Tqu*@6Cl2$uu~IXWO<88ncg=eRrx@DE^q;VRMp z?PxLO46vjA!%-pvoF&HMj&hjLmnPI0>>`g?u5jYx1_bz$#)rHOfO>JM3O5#68(|5J z1|^-bC_`lv=-no55MumTWDpw09}QB3ym$nV1EWGigbjIEqT9_6A+ry_h*+l|Ithpz zf+#3;x-57+->1Wb$x3=0AEc0_EWFPyr-bMhztVlgwnWA(LpKc~W3luPrVzGh*Q{V$6&JYhGSTr6<47@We7vf~|oCFqEO^EU+G&+$i z=Xw}2DjH1K7!tp5`{4&C&Sr~vlmKD@gt-x(KVrkfuL%GpgBO@|d@K})7mEX^Kg`i! z2(fQm(9nmcvo#Sx#4pki2^O4Nhs-NWO3-5nVG@T6TAr4OyTQ&i87Oo>wlO$>QU$BE zswonNJS3wBWM(%FA|q}lPL8vJ;cjv&V?dY)n5h=8QwduuOA(+6fZ#GLjsjd3fs?R% ztrS}XNMk^4)2+mqHG%d6*$`7;!x8mXvBfO0>gWcyKqCX@N{f~nrr59?7TfE?GX+Qz z2J0ewy?~$^L9;YYWL5)E+Af1?QgR6w5GZ}{>l$)q}ua=52DS^s77?cC^q6LO# zQhhogq49%0V5!MU7bG=l;3)-xoE}a=w?KV{8tXtr%^232BYH8HC5nb33ObobA|Tp` zV~1h}vCyU$h^>-ngm3o>4L~m*$1$NS9=IE&EPfC!imx=fZSgpbZGdCUMltM15}Af( zkLo}QLwvel=jQm;#6Vak^ZS4XQ^hqAXmX)I7=SGsI7~=7uHJ*?YQ%t@X;Sierl3G# z^NTLXUXvbg_6k%xD!#Q1<3}1$B(47p;VHbPzS{f zhru2N98oflN|v({EJj!&utH<0M=G{B8R8$Mp(Y<$WP|LI61u{)DwoiXN%(959UJGA zLPClLZOU$^&c+NH0fdL4AX@|^bPVffIUF`LJtBA7#bjTM&tL$TlssXBIVFkAh_w?3 zXTU@CLGvtLE|Y1sqM*y-7r5DRJr~foym}enje0Q3kRfK*L1Tc03sr)C9>Cy$%_$@V z#Q~6JtPA5NV*p4O5~_)C*lRHf?Ua}d(b2%J0fPt<27vZNY;!YKCv`LEj7U)LBuT(| zhC*d0vauOSP9wvrr&z)wlii?j(0D-IBJ(Kim?)Zz0nG3?P#KF23N%1)g2UjAg;@N6 zR~8GX83qqNB4Ap*1c%Ip2U{UXk}IQeF`Xd_3uRW3Rb+D$^+63VE%4)1C051&n7&}d z6V&lVDjpBnoLF==ls1DMc&w z2AC1K6e(h6(V)K$#)8UYqlP4lYbj6~?Es2rhF`>or2=$H0v`?v3&a|~gy4pd86@p} z4zwEW$H6wM5+-~~sSL;nI0Tv1;I-P#3Qo+g#5mOfs}P*ElP9{=am?Ew2*=+WqFW? z=>Sa$I>aF~VA(1`Kxg;Eo7xyzY693>8PjOg(L_QX1{?JCI0#HcoZ*Y$2lW7PPq)StkGhoBc#KPAY2`s_z=bpVm~y+Gs$%1Xb}`>= z2)o!8r&j@Vp3oT)B$)$fx>rQ^%C#y9)9IAh38r`q)FhSyebO-Gu2$W$ETx_+!}X8Pf3X70YD z;4^oKqQ3$RXZh#1iPe0)erkx0=}B($PMR*OK11xtrz3HSif+G-_A8H@n3d%G}1 zXp8W=1w0z^T#Zy&R1JArsoQEH;snfa*dZ{5SSEBBtD-v`L~C3R4NXWfVvwy7(p?ES zH_Og~o))45s$h&bGW4BVZ^zi&?um3Nz#-iX6)QM*l%;SfumTzBg-RBLH+ z&u*MH9eJ(3Qm2g_J9g^$%w?@}E-(`f3zvM4cfD>5Ru}Kvduv~@H}+;?)oD@O8hJSK zQIA$h>2>SL6pGd>%F1x3D_^o_{8D63%VEFr6R2O@-+qbpO4WYZ`20eecKwjk!?hF4 zO`FXjXs%$i$4#B~rqz!3sowW$%KP!|1}#%^s>!%*a~9VXWfV#3vjgbrM0SIL+e$tk zvGjf`dAR%(J!5bpdE55CvY#y<@N9V@r`DSlm1}?RXOfCuZD!}*&WKN`-dFgZRxq}K z|6K$B`0aOkPN^S=jd*`|+_0^MqE;ovhKg;Mo0JSb(IPpyHZ`}!KVKTONT$&^o#e9% zD{8gJ+gGKhH)xPFe(Zm~?5E{&$~PCzPt^Ti4$n=V$f$Q`8F%*o^3PXol4zNuC;fh@ z$NxCz_}p5V=_qWi`ohw`4m5b2rNqeAqJFx#^lL3R?98$iD^fGG?R)Er(+fMbK+pd0 zWO%oH-=a>Ig1@EzaWCWknv&Z$rNof?^wu_W3K`18vH1sy%R zGUTnJFK^H6KyZw>v_=|xzVm7oYt*N|pV%&~Y3aDK;mN!0+5xX>t`0Z;b#3dlt;YJ9 znVG&vi=*ozx5s>bt{w37%KKY;!bir}ZCtou!Q(4Il{Ib9nEt~?y=L|t{A&~U&0lx! z={x_y_Ye0AVqa^nZXNwOg6h)c?y-*EqZLJ2{<8z#AH4Z-wsfT>Wf1P9^t|IO6moIrKO-AKP1zj+I~@aK`2oLoriX~Cr{op*fjYg?#B8_jMAiytutXs4$RHw{Bwd&I4zxQ?9=^lXP2BF29Is+5z7n@5}4@MDOhxs*Sq4)BEhN zCH^j2L>~8O$;f8w)tgl}4vu`euU)Hb!NHaM`Iqcv^AtTdSw8R&^#=H_T7o8F+AF!Jxc>aJBXJ zWfw2Zz!(mET%_tM&fQI!eN9-3Z`f75#-4%a#Vupe`ummzD*-JUmrWwqtEo#r58vT^#`{{{C@)@8SFVXNwk1-TQL?VCDA6 zb6u0P{+iM1eTi_*;wu9;b{h2k%l5t>SLQ!?b@#~S;|IQf>-X;Y%_&zl4qo4M=;q4o z{g+DL{2hN$wfm{|-RHYgI;(aCT-UCgDlR#C_SCjfThcglf9Rb%cMeThquIJ*0^``x zqigon-1Ht$);~Vv`0o1e{<_`@XFU^2kJLO>G9OQF)@j|9zlyu?*Nv*0j+@>1L#L|& z^~hCYIJ-Iz{QTE;N9R>T4lx49MvwiBexI)E(Y{x~StqLadBKbs3iG?i=joN0{;yV! zy2B&pNS4)_)p^jSEqBJ@9{h6e$k)No<_~+P*%Mmp81!D8wjeOPY(`coC;l4NWO`vs z-*g7tS36WdfEw0(z~63-B(saWvh@m_4t% za$UC-+&A=#ty8+E?CQECMsr(GyKe1`s*lcDICE-pSIejXt z;CYo*T%6E+;2J@{!8>f@KzO^K%AXy~`#@@#bK1K*2h*JN4Hl{X?%_$jPo5WR2IQL- z4xLMizcCSd|3xAV`Su+SmOK=s&NlopZSCv(e^!mnw)r8}jPd<;`cOj)2E1Evp=U9XyRFE^gpap-iaBmlD#lN3Js`E=rap%WxIK$qRMMX_MyU z_iC6%YMqkiNjbxHc5c|2ls@|2lkC%7`wZE&?1sSIj@yvLOKJ6PVRGT>si?$Xt=?`O zc;$feYHwvKiTkiC^~!8cX_CAjcj=&FreXG=yfNlCCr16%oSU+<0QCU%JHBJ!MRP(q zC^E^1ZDW9arg+efj%vK*+oOFYfGv-oMiAjzu4Y?&4asLui9Vm z`=cHv&P+HsfA|>f^ZZfsa&WuH#&I`sHNQx*mmMqGR!1n_d9;rFM9coRhlh5oe-k^m z(cbW5&$n;Js$RCLJexEBTzGO@#pm}g&nk$^N98u{_4(Va=$|iK5>tMh4zVzKR)VPOb#$z+2Hz?Vs%O_S(H1EkQx_HzBO zR@}E8)ep9APGt+XpYpG|Qh3AQIn!Toryh6Q_(AD6}+H+eAIIAdX+wD^` z=Xbr82&x90X>EwTSx>6FiddXH+jzHo3HQsXo+lfyirGIbtL-h%&E{-+hH?(MiItC`S4A8F+}T1vx~0` zxHNuG_X3?X?Sv!WG-t|YRMGUdy<{GI)yQ21TLmv(R*7-5g&%sp=YM*BalmA=tPa0N z_ec9mNA|d-!e8y2w&ZOK6{r0AcFl=aV7&H2RIg)TKB^C1ijtzP-)p$?ZGP5-=Xm!G zMal9vM+;D6vs3W}8JK(doe6XCU)k@UXyKB?ijro*L z_I68**!_66@4~2gy7jV^ytSKm-<8UbHJ#kCOo=L9*qlq|w%u7&b?`|K>Vbitc_`X&&d=g4hM#+Yz2uf8W0|`Ng_aHLAFSM*W~=bBCn;wXyfl{#wX*V=6r>onEoO z&=wGIGb#0|y6w&x^y*+89-Y74>gZClf77K;Z<6OPuoaCV^y=|-cr2EIx^Tu!eVUS- zJZ=Pg>@)IJUoqpw$^Nm8^3}8Ywys{DIy%YT_r!$$y^5y3u63=1v90GfN!p#|J$n`I z`tBQaVQ{x650XAfI&>-O@Z`dcWAA*;S1)X|an`S%TkA|IWe;9|oG~hMHyiV7t>%-S zs9*AkchmUmQ%{hq9^rv%F|(%riK?r+kK0Q*FFsanp2Vp4d2sgER>|W#)-K?nGM0C) zm0x#sUHb*jM(N3Uz1lQf5h*A|eR?l#%$~XAVXMm1(^i$g-2ZtK{WA+EaLlr`cc&iYo`{B+miuCx2+gIHkkZ?Bx=eT%ourI2JSC-vi$pk9ZRX(axVq_^D*3kH4D?4134#rGbg2gDj26qeMli#pmmJ;pgGTrj@jqdIxr z)@(_AH<+JlEbXzidC%#q4_EmpdB5yf#wp4iBh0KRT35a4@||JmmC^CJ=!}E4Y&#ZZ z*jM~I>sc>uOTyG47uOb*vx;so(;oYqud-(kWj$VX=;be%h2_Qdr&a}b%|D-%U;iL# z&8F(4w0j-8jJ|Z|{P3lpvzxEvp0jN|LLa`5P;~yy-zeGiGbfI?UpRZtSK+H}4ynxU zU+dw1M&oXKyoId;oy!O<-|yzl?Y?q5?_S!i_3Az~^n3g~dA)J1QrZi=v;Stcs2I~= zB7@CdZM(H9-@)SIZiZ&f;(ezy`h=>7%CC~dlDNHEe}8Dt-Z>sM75``T+ab%=n#=OL zw{t9Uy-^e_Y?j|mNU}GgH_blHeLVd*c1^G9obtB&9fC8;_jq&iqZW~n@4gcKbcZlQC3yKowNA! z5n;h->%rO%1^3#n-O^|Cwa5b^9Ncu`{_@)S1D;h+j(__Szbq=v2xe8+)BWZdYS!^j zX9$;G8&j+;o$nYpt;xWHqt4_nBt2>@9&e{HT^~{>70*a|W?TLHlG5#sUY{H@eevHK z&`uY!4%Qiv(lKR_?sXygg1RVwWTW@;(#QqcBvn^DwF{=Y@0pjJ@@{oroh$hKOPyEf zv1unSy>qAoRMyBHx9c8_Z-`Y?9#Otv>d?fL0VnF-s2RGXkh3vO_w5|*Ay@;7L$7x= zH)k*0lGne=oX1VcA)O0Pu&kfs{TpOtVgF?-mCd-M_nbY8CDVCwHTQ?%nw*)GQQb>- zgxeq0@Fy4g$Nw87ZEDdXB_~M#54ZLIc+~0g_%#+}@<0sOQ1_1%nP9XjQ!V zRa(lc;d>bO)@r@0Jdou&aFfiAU$nnflPDj0uWlY>G`VGsP zT}qT?6`~5Jak6W1tIH~LmsI8EWAzQ1_L;bF+MvldPrhRm4Z-_Q>nR@~*zmP+m*_^_ zz>sX*Kku{@nQJf%A9<%-(H`Xn&`Y&ls9F4!$)%t7$@h>iwhEMT z;iwmVlS)`9ZnwEAY{QC$?YhY^$r<{O(!Rs9sp4FnA7tu9p z_fxp3KLf%@Qx4XBX5?1Bh5~_3Fj)Q1XEsq~yhVF9Wew$hzIgZj8ha=EwspUhi5i!@ z>%?90>HLmD`@;<###MWDl@HH0pR=(MYBFPmY01rV%UqqS6x(o_w4k=$?jJ5>&u3d& z_xvf+6dO18wu8XH7Y$2qpIngLwX5O#?wy+8h$hX3SCwaO8aDsJDb>Z2^{Z-C?n&=^ z)!yaemkh$;H9HDAEEik^Q==GF+~q{AF5T;>?`KI+(Kb8QkemEAFF__8UjOeqZ5vWf zYyH!m3Yc)GYkl>G>GArZJ4U8A8+vW((du2#K9+6YTsExE+V8W(jzggfV|sMv?90a9 zEw#Yo{30AwIkmwunJ`@~y~A@gm{z@MqKL41Iqz=Ud1D>fuW{RZ^85Cf)aa+hlMPX{ z3k-CfjcXQ6oUPgO$n5I(`aw;ytTT%JIq$~YPR%wNOHY>x&d|^~3VPo0t za^>dyOAXA7X3Kbs6>igzq!t}gCYS!vZw0;Py#&4O_qAE(A9pD4mow>SmC_az%7r9J zo#hp`R?i=C_sqauEk^e2G*0maJt3X)rRQRC`M{;3thGxnpVEZKh4I_3geG3d(e+r` zYk1vm+D=pXPWp?fnKqdo{i5glCYeXxF08ll$7&HgTh{ttp2&a8g=XT|LeBKDHIEEu zkEb2`eNgA)-?k50SGbP%am}rdYwYcDnZ=@SMORz$=TYx1*zk7rsr0_Lq2I zKYxDK-qaN?#%xP~wwkI$gpHjT3klsCIElC>wGN?!9lk&w19S3e6Zq!}& zF7I?ZS?9G%>$?sek}f%$O{`vB>F!<#V(4RE-w#0VzpN?2XEl6{tHaFs=bn?^FZ1B% zR;j2rd-m4eo|Q?x{iyL)HfH2tb!y-5+xIk<6>;|EmA&|WsoSczqc1Tn;Zd_%m@TFK z*ew|ot7WzQ_gWeJgm>68L%v+~i_72Er16X;k;_vq3~|(s7LOg=A!+xCTHHPByElHc zZfftHgP4T_}`uZ?nL&-?ndyWyU=->A-uU*;*w zvBJicX)7-Zx*OV0n|iK)w~_<(*3H}1xXrXn>~BL>7UKFBU`aFiyT-47-R||-%0IWh zJy$^f`(?951(cabCzd-)xnK7c^_{JD^jTk(JZD|Qqt7@d4ToH+PMvINGh9~6{nyU@ zpAqj7os+UyGkl6{)P;dnqlaC5@Zq9n$FumC*Dq5cp1bE#?y%L11s6Hl*-1GKTXsv; zHvCQTcNzM>m#&$_Zz-bT{U;u1w($>f-kBrcjCtw3 z2d3q;ZviuGx_%VlrngFRQ){%OO@jnHyC%NZOKvBSqY z)~ojy9$50n>*+V;gqeShEWIM#Jo8jVSL|y?14Exl%R~G7+QLq6m27vfMvr>UJa_Ju zpe1Vg?F(^i9hP7E$eg#Q_L_^SyILq0%2DlAEJUZQDLi9lyR|JK4^{GvoY!zaO-!NRYCx z$D?s4t#k=lZSG%%?NH-!P3gb8(Vhnj7Zm<7Jx}C1GUJa4udjZa$>H(1FZ*z5C2dEo z7BH7ZaOv6Oj%|ICZiq)7+YB3B7fSN-|p4dB`rVrzmEit zvBqo4?3pzK3-{#qYceYMQP80Gm-*w%KS=(zks5XC*gSXBqL2M)XbPp_!f2mE<#p@4 z`t!*VN%n@)L8uAO&J7_pT%)P8=2ER)rAK=Vl;!PE^c07icy^rZmGn$%e30>Vi89J5AW~{KMhU)%dv?gtBfMelNZMrv05Ne|k>sHDlDu+O@Mo!yr|CJJ`!P20Sv`JwA&Ih?6=4`&`m zZ+WKJvHPoi^Xm~4uRZ^K+RX_xc3&xrS{>+uKw&c1W7r0Ie;@_ubF z%EpWCpUW-Y`{Ya3{oZw~&1!F*FK;-cXnYsUgO!~smhN5izG-dWr!N@6lJ7~X@7R}p zQ`(o*U-M_Z+}nz#W{z#0xcv5pnsFVw-k+g=~B}c{IX_Z6Q4{JKT|37#1JF5|E zDJQe$(-U;b%?$&(s`VH45Md2OhCDBl`W6??X|d=_*SZ+1{8{s+b)Vk8mSX(03A>Tn zFyH?na9uNMkF9k|O3GX>YG)y8+sYnEmtQ8Q9G1OYje`BD{LRcJwQnd#b`olDUrsHrC(A18 zi;YL;N^ROFgv~dMKX${-eY-UO*;s6wvFtZpQ;1|RyM2~!&EXvTwd_yBL-FFvmpjbr zmtj9V%{eYiYcW1+udLA5MfkbhJYMEYC$`q;mrHGqf_a;kPHKK2b$sLbXI2$gv`){< zSaxM-E@Mo3kvmAu9IP7CDXLC;^8dQ?dT{4AYHi!RegwLsBXjkaYb`5zO-mfzdG4}L z!p+xOq`#vz5d9_ox@1+^a{b!UgCjfE9NONzbR_Bi3c|(K`7?Hp%27URUr({2>72a{ zr-rZ490QB&H!6rq_VP)#%+UijmXGdQs*7khZ1`8szV&ZOU6?__MNR!LD_k?%gw9 zu%~w_(#?i$io8bmj29PfEB?JrpCR=+_dn3-W1tOjWe;obMF-3KOfh`ib9Qcfr>Xay zWA$>sUC13m`()d2W?&I&-eQOF@ZtxbMqY0FBNQ6HoD)ZU+5g-Ux6}qHCyxEAxiYoi zZ*_2EMkTY)zSw0sT)JweV%3KEW4E)%l}}U*;xKQ6ZIzXI81rg*!TB#&j{p9mQJv3U zc6wXgUUa*0{bt`MOeObvi$NnPJjQMA3wG+KMT!Bw2X=vmwer|6 z?<#()n7?|e`c^)F*E9psMr zGYz}fCoVVpKbFzuEk7&0+GBG$p-^aDtJJY;)~u;z+lD{iDtXhSwM z&&umwZP>Ja?{D>o^j*BJcF2}Vc+gd_V zud1a#t;(6Ty7=qom#EzuVr@(d}csiiSes$!;Np;$No3JNK=KpQS znhhOFE{&PrM_Om-;3n)_>)xlUXMK4(j9ZqIfk~V4{npHa1EZVXY~Gt%w5_t6Bxyvt zO4RT4`}3D~rs)b7-#j^JmM1(AquW^hv+a~zdv?nfDR%6#Z$qj!8P~tQUU2r#hwHbR z9pDsmiz}wD9^2#55N9U$P3GYv(%pZ#cl~x~`x^OL!kb6EC%0HRFtj+fuj29tKKaAT zNY7j3_Iasa>g}F>G>g5YbsNR;yLHxHBtIn-CuHr@=G7^<^tH)vb6z|>i{{__&&3K$ zcib}ih@(?m&KlS-zsa7v;akh!s=xiw?pZy<$^DZ!0v?ax?2h9ukCOS zY_|C3)bcIsmwoKnuska^>qS~csCGDXD0FR!?4xt})lPhAH}ywAJ-ML#$AhX(J@~%C zxb!ENjXD`rT6#xGbWiZV^6%(vxZc%+r@WmnTGwE0ONzW<_1w38gR0g2 zvNq#_UB(G;-UmC=@#53Pxt11_l;X6-r-vMAk$+`p{rk)N-OhCho=$xK+j`sINVHga zwr!U-Ao8>DEoeyPS4yUCC|-3fpTlc5s&wee+n>nbqMa6`NOY)du}t{Tl64Pyg6SM(eZc z%a|sXQ$0X+p87aq6un&hPh&BWe4(hKH4YUR`Xp0Q|BR{M=(`P8^%>pvz{{btjvkFw zpXxMzVl4fgtkD{6DEZv^OM^ZHtDC=4GUmjW5 zvP1jT6W+JbxO6gBH&I!G->#m+G_{@W8LPqK#w2$1SLy$WNrCuT~b|*8nSCtBmS7u@h?ed zbB9!LQL9nuIhdIoON*5?dq$>1WM_Ll+1tEJMW+?=>yqkgcXbH`oz=EHnf143HCnOPd919y3IxF^j5pR(rN(| z*w*Pz&&!{mZMoDk-W{L*xNW3~_ni1Pf2f%4_^*j7C*;3~(&qlpR|Oub$@c>iM6LgT zLch-1j+oG5_t=e#KRNX@zYYV|?zxz8b{pIa=G|IoY%S*IMtx|I=*}+Uv9f-e8~i1K z*W72eM~fdB6nk!L?GTB%Bme82d_ogUN)i7}k`ekW zsNtFGWB_2>ex(O7$p?`#_SU#NMe*rt&#{>~uMGbfD>MIO+=%bB+o$;Si#_Wli^it- zAq^2m$EA@?0?4IYD%9$-|P{f`8=UmO8IYX+1Lnd zon|P~*t@zJM1Kl(%Ql-RRk^;=($j~mPgc)>3cQx@NQn`1CL&CJWw=PlW>m1LsmXXC zTO~Wp%uxx(ZzvO>ahvSd=veYS2NwZ;Lx~XY3p;$YnYxk`1y()tYk!XrOwn#OwACLQ zke_B>SIVW9Myy0t_!fILKf^c$Mnu-}Tl*)}I8xspW%l1&8tigGXyjT=z2_irdHpt@ z9)!7Nq`8m8YwQSTlra80*QsjKvMyU$S~!; zz^DMZL~>GW`!WI`{>p%>f&)-b=+%^zg2BwpjFur**Geuv9KHi^ES`&!`txAIn{>Yb zwx>ha!J(4CqM9NVqe6#me%DkGERqr;@u6uJ-o)O-!vDJz=5X`Ib;Xoc`S(QO@TsJL z2w_FTS(2U^F^56d2IU=%jyIUM|FyFEu_(y(>|8$B-PM8DyFIcOP34vYQ3%YtH9(3X z%FMbV*c3_OaCk1a)6uqRD6_1g<#iM!kJSrcoKY@3iJ>6X-rpX-QKY!B#;r@*;}JNV;2{JMGZ-xI6#fso35A6483s7z|5&G`AJ_gcu*Z zM#dlsY3+l|vWE(ETFQE4Li`A>-B-$-{?iu8Da?+!8zj4nKAnwJjpA?uFx;2dOW1z6 zdg54>lX=sRAKWU?wq*bUQloJ(PDA-xACB)B2Q5`j`+NuVm{u>d)srPvS`w7k9slQ4 zS!DmY@B0P6$%4X0-+3pLz}!eF{TCt{w(`Tl)X`nCD%rUtDG%4!M56|o)W08skDO~Q zgI5Jgusq?l(*;md*{`pcGEQ$_Be|1y%50gSl!{FF3gaT{NWAZy|Gj1?9^RcIt&i!Z z6*f!LtFTh)KwT(dpIQn0e`|nmSbp8akHI2e(ao3i*iC-biVy5Rh%mw6y<+m-RokO2 zDI6^`4~N8^rqF$F^uPA9H|@b_t*2{t0y3fLah%|TBPCcqum2hevy4Gw!(!oG|32ME zvHV4+TzP9IjvScXcoRdy{VKPu3`m+ty7w=?Yp2xema+dChk$=wxdm#31Qs80d3i)v zUN&&h>i^gDu{^o;F$y01k(q0N<>UBLkDs$i_qAaI?C^gUS-yk=u$Y#bdX6YB@4)>E(rEF0L|DXZuG^_{NFP2WubEEG7i+(J%Gi%i6R>0c*CV&5cKA9 zLrTgqi(!8#@E>IW7NSG8%TX%}@b`bVqB)1Z zgJPp7S5IiB?GAwU(%{;LjlC6b#2iY34aWGg@h{U}>QS$}Z(rukhb3N9Xn0LwsX5At zHmGs?R9hQ8eoEs<%6Oken8H#_O}I=7;LShruz`Pf`(OAV)|dYk`=IelW4C71OXZaqwS$7kN_=<*wu7sV|)P<0xWijl4Qiv^PLKPU68Tr<(4d&&~DKlh^mR6Uy$greL#|Bdr+`d-T`e&hr0B-DMRU)Gw#7@)2cxRMa~V0f2py;luN`WJz&45sNps4c+jn9Ou+i zjj9~4f^F?PV8|WTCnTtNG>Kd%oo{;_tlyk>kTF37nAd?M{+V zt9G%K+G?WARm(&KYRm$Tx-p2^=RJ7$SS2KAvy`IM_eKhIdU|rA7P^F$AkrldQvOc? z^(}#4jr-0YKp#FWHMtI$@SOV!RnHsV;N5eaB?1Kbikjl1n7erV3|l42Hfqyew&t4gw?HAba_V)2(GpLbm~rivYo$<_=iLLcqPH z17O;1f6Scvx#xVmdBcw?-;49hIN>kmC>RtN_yYISP`MTxkwx-oV1G zj(Uj9P8*-vqolZvo%JwquVwW;Y?uxH*Ws{L1(jhs&_VxG4^2!m&;QB zRWO?$`%U_7T*pdH(+HyziGDUPQ;hguBg=R-U6-$HrEKXVe^>9bjpfnLf7cZgcYopB zhQ*``|BkEQuLp0SSkD7y-_!KM{PWWt)yt?DWTi|b1O0iP2kT08tP)U(Oorai zw)!^X<)}8=-@kw78r9d0@3`j{ikqM94yZ=2++0~2{lo?WKb*4ZNTF`#-LEj7)OV5F zAoMD#w9u_^+j;?HPS)`A~jOoPcmDvX+*wBhxJM#{Jt*%qg`}&eg1u!o$E2l26&d zB<*qOci{=<_NHzQqt8kB@niooY#$$dRez?P3@v3=p12F_1pdI00s;soxl|c%&7V69 zJtcLrE~{~RX(*nGEr`QxhH4R~>NVZeq3lANkP;*=J|w$OVq-~?{qG0J@~ej^t}5l& zN%kz=7K)L2lD+Z>;H^~GL(pi42&5IgfMHGU?2YCZX&l(;jj3AtU7gwU$14TEqQO%D zwZcao??SPq|A13^1l6w~xo4MJUB%whrdn^gt z(hQqbNj371)05@L4Z@c{IWplV^gE{KXk$1ke^$QINxUi=s`rAv{_xKYtpg+9vjE_} zdFHLqh1)-vs`b=j!gd0e0q;#VaYDP}1k{bx-wVKk@}NksLeOo~SSygRjSDS8_p!|) zF|1pIZ4P*TFvrmFzcJkTyElb?`(c3y2>171?EB)ogXcFH?me-*Vd=aJqUL;KF{#yT zDUCdJcIuDe^F<`1EoUiu512SKK2)uJ{t1*XkhOAEy>%p_?9y?+qe6k=!xd}`vtgt* z=Vj^~W)KtZ3(5Hg?Z#Jc&}eRlITq$NUv37U2d@(ycDQjfV9Y`F*Z6R&XOiXZkgL`!9e5olS+rkU=N3<15&~y=fR-yU%Pp_BMgFa*EubebS zqJ~kWHsGvrNS9p*c+uib<0n=BCoU-mB*e{5Mi$_B`Wobm4JC?oI^6o8X*%U!px4wG5@2Aw}%dq6^#O>HI4L-N9qHi z{=NfAF?F%Ks=o*y?C2(B+Y6a{KEt#EqZqd@enLjXAWZh;`^`6|7?EvgWa5pE-`Nk0 zuCrng<_=aex^E`GKXL?Hrkp)1i*=g!OdcnuFnT^SDkqLhv3D*2Z_9#Kp-j6=9vw7C zqW56fIggzEY3c1aXy>G?7bkd?BM40m%0?wjKc)Iy6 zJcO08EqTLxR#@al`VvoDmXl*QGYw7lx=KcK_`xHyC=2axVuFXH;-*$tnLSs96kBci z?(_asvgJ&kq-AKOMnmzErQBgYr(23ciWF-6s|HPbeY#8HjlbkXnA61unNheg8F4dW zX#io_+z8#hEXTiP#?vKOqkm~m(e~Yj@XyTidng9J3?{G52hR68S-f{uaAp{e{Bpq; z%2$}+!m?~Xc62$U(V5rp7DXd>7YVnPLKZ$x|5Z&|3XYj6-5ba`WUOgw)PBcp2 zO|IK9#dBT4ly=TQ_JYPq`(!?3cDfyAs-|yP+>$Bg{FG4FCzT2Z31K!lsH;SgX>^Fm?;WdmH zUG5ZjR>{wbIhPdchyC5GLRpMoPm8O^%x+2Jm)m80#_)@U-gt0>=U7Yq`=Xa<{DwX+ z-zE*7yKk+6;E9X?6n65V)@XO)e-@COP6H88#I-nKPyKiKcng+~a~Q>Zxqo(XXqMbG zlJIwW+sZX&uQ&Idm*X`2qWcwCyE=EEJ0riiHuZt!f~U%>1@kd|JP#ynRM1LfGTK_Nc#Q6$5By8v>AU}vH?VxU)w?6bifI)6j5k7`303#9 z!?&~W9yeyi$OKGBwO@KAGyi%e|K46)AP^WX^N$4NK(lb#4X{=be2wgP`w5I9t$Z3e zOfBc>q{hR;4&n!ML-z^UTS1v%# zf{0Yw_N$cnt-rZ%FY4de;MFa|HZy!6JgEHBcTIr^y^FWVp=mkqk)Z4J4xS+R)Q$!i zJyaU-1*=;H@$Om3*f;{yG8X${+0+2RnF(&8`yYXV{j2}(jU%D|@7}0746@-)IyT=< zZ~&W_VQlZ4lgcsO3)}edg zlJtDSw^f8YVAZK(6;kA41WvOGZZ|s}%B*ij9gL?Ov2LVG-#dB4=TcjL-fv_X0CC$$^Ji?vBXnHQ z{uEt{J& zSbQ*;;7bTE6rH0_7639)=C?ZP$h$y<2dIKY{dia-fvaS8l0M zf|$FMv_T%BR&Js8@fC0uHv&1g?5-0?>JOI-O6-B5Jh~D%Zx(-63MfT!Vdl!}+JAu= zaxv;M5DDvcFFP?VuL1T`{H{dt7LcmgEt0ch0*$fCG%Usyn^q4ZvygIYIeMl2RE9{L z^g!40K`-%950eRg0Zk^Z!G;#mEdFsGJ*=0x!_J5f{qVtMf)Yq+ruscaaV7}V>}3Y_ z&gys%xaV(b^=TOF`nRI=rg}K0e30mh4<) zw6H5w{lHECh>BbNimJ>J6et!2?^&*obtg-z0p}tKy%-5_5361yxV{SV%6Hrv+4p3^ z!^2ySb`}`j7rGLIfbz`CS_?*UajYzdV!YaUh0rSQvdh3Jkj*TH@~MH=`?jeGewmf4 z`GS@RnkQq!ps>PKWUj7GK}^l_&O8P5S5yVYW_<=Jw_Ddp8RX86_qIk~h95EhU7XHG z_yw(MF3wN3>MzbzMa6hwOQdM%SfbEN!aslh$l0EzJ@6l_E;VVR2={Y8m~_>07pOli zjX;L0k#t@wqA?_(q_(U8Bm~lP{_W64I`wv{bn6vuzLW@jVGphuYr^3D*xzkl|L)J= zT}c6<*idG;3~|EO7*HPs_wpSi(a~lBO_+C^mx8_gVUmOs)e`TMv^NwfKz|6vBOv6G zN0eq;LQp)qgdOzac1e)T?%B|u{f%j6s0W|^XLwhFD27*uzoiqjIxwR8G`Dkl3ex>1 z@TU-BD}B28Jq;0U+D{cTi?#g;5~MrN(6~5D&;{YLj1V2q_Y;LztC^?H(*r7ULeIZl zF~yg1T{p-&Gm$J)0*l4CDSx!qG{K%H6NP5sQ=w-&C=T~q4{Yy|-Dh~4(70GQ2)BZ& zd&XSj8qD9>^mjVmsJ}pfBvGplh#>g{A3#Mi-~9k2)vRJ-G>YL&3LuTR|Ngm;)h-(Z zGU%rq4>KKnaGgxXjp*A^n=5w1%nSwALJ5uk9a}K63vd1%*;=Bj2;09S%kl5XK7U>J zzf$6>AJCmZxOzmkOL!B|>YdwH!_o5mvPNI*(;@nUdg^Xw85|Dd<(6?Gmi^99N1!lW zcDK-ykx{%kztbb@J6ZU}{`Xr*&Y+Ka90v+l^&AL%n?S1KW&P^3(7h}%pZ0Y3rgO+D*)nF$v>W(j{VqS{xe(pY5k2N$R(n>E$6^aa2CqfnbM7 zb=FCk;lMYuhRnRA6cqIk((W94J8)qrm;UFdH)Eh^@uK;xHCa3-vFK6iS>n=)T8vJvFIOuTor+qp zl!SSFsCg^pPZMYc&D>Gw*?9-gW>r;zsyqfgO^QSy;L~>vz3$Cv>7wL_!i&QfrzF?~ zCS5_-VfZq^%AK3#59Lwc@@k=jCZ*B|F4*}`REK#gI6)O#(u!c^#Z|{ex~h5dlHB6VPj5 znN35k0(sb-5pD44ML0Gf z8pO_8`=;W4O4D+HeqWmNO=UgI*B(zSe@gY+>PIAv^hW#ej&A1x>U2!&$IU0Ny+2DB zx>Y_}9v9oS?(}h`#!^HEz&-H4N;xs&BT#;0y}Az|+#0>x#h@FCl1zGMiq;D+!g-(x zYHRBXpQh|BKJx=hZ%*N@vS9i@YNkw5R8b%d_OGRm?9@o8gN*|2on^@#4t5(x^x(B&Avz015GQx5DnN3sn*AjBG=!LP@?DON zhdTBQv$^5cEheV65nf+j+>(E&!Pe<>+N{2Mye1gvJ3(+nJm1{kBmR6ivBTldrfyV$ z9z#!!gDhP|LD9C){{BJS$#1$ON$O0I4-cm{g8Qk1)1FnuGJcdkSEna&ThZ&434>2P zt&}P@2>$V{UNNucnN_&lhos-5XD83Ep$+cYN}Gl020G>Nr<>K%-x6K99+js_<-}3k zeCX%2HSv?|MdNJ6`zm|t=-JY|VBhN85=wC{T~?H(yKlBq7VCt%N^% zJ(6D7VH^#bt!S^COX0G;9_#SyJye@N1UnsLI~FhjlIPhJ0ZQ?phRD4l&Gc>>^omf@ zmFMMZ|1EXOfgTdU+)brZW9k%UB90au^yp5NWd_XybcTH{mG0?qI??6(Izq*@gN0b9 z&5NjbLyskP&<}?@qf?(QSL%7^+v?OfcNpl&{7HjU)KK0l^QXlS5F_H;#UTzp*>Pp%K$gsUqD9S!UQ)cjn^8p9J&9yQ?{U`@eq*7jBI(yJY$nxH`Cw zcq|@jvUPem(SANFXWlsv)@}+j%R56%=7_{b26>0@3OU4mI#=jSET`F!k|pa2TYL98 zTtsdQHsaMSN-^dv=hS&-90tKiu(8>{I*RR^8=E(-w&YGPG~XFK ze<)IuBQ|B&d(B8yH%R=XOM84EmQyyAHZ$heNr~9ZOlsht`M?p zsy;sTlU5w)I+ae%}5CVya3h=E&`y`!@4#hL36KmVVk%t4V-6;O}TyvER-px6f|oLQ|I=48d} zhn4glOw`esK8pnF(fnf8;o{!K^X>eFXfar($myr>PrD&TAGc@SsCZ&j$y;;i>%+{a zz5dzLpLpLwUxPL~n11`XcH>)-NZuHWm#(7EIaTw`IDbR6 zHS%~~eCC?dn}(-p^iMfaCO;Cg?2lgDbzBJ1q-$?k4r`2#d+Jr|iSvhB&25an{zr96 zg2r3X1>Q5V(M8vK*Ae9Kbn^9F4Y^*XE-$;ZDb$4IY5h#l*JcLmgov0;ZxgPurDrm9 z!H;6}QvtrR^3o&movYNBQc$9F8&Nqq z#Zp&?Jcaw==5y*f5lPPLg^@nHAX78yrcDr9`PueMMo znlta!2FnScyyq(5mX>$Pr+;@G_&m{TYn_nT94t8amG^v&1k);HwAVC#VXM)jP8rVz zV^EPCZY-EI=c3TfFnAv7woPgCte(t4X9jaC6{oCQKPf)`0FqNe|5kq^Klr<+YKBI| zNT0XyBN88hp_cwcD72q`_jExw6WVV>+iY``LQI$7gIyHDyxF=KukehLuozlM0{WSr z!l%0wPZCnq``{Ytplin$bqtO(@bz>$A-3rQER5!9B=8GP>(RTX_59<1H^^G3OPl-P zV;2-tb5-8yYX5n*7SxnGVFjj^_v6zJH##&p*l~gqFd@6UqMHYcg(>?XJs7xSgL|~1 z%i~5l$iEr1Q5S734NQ1Dx1xviH}DhR;LZG`hiT&MC)O+y&_Lq$?&xo&c$TH~3nVo1 z?v9XD$u}xfxEn9jFRJtE#lQ0@Uv_^Nm_^ajR&qvGP=C%y87m#cU2-9i%&~po?Acen zI5q$ZXQ@DKt-AT-PaXQ6?9<*+hFseGzxRqv{{>-|`6XmX6 zK(>n85LHcfmtAKIm-^#s9HA++Nju3_x*U`fCcYzmV0IH{pC3OYIj!qCIX=iKdU$gn zCQn0p?dyz0mqEqw8g*})vkJqcD+TYuS@!$6s38I4o#n~Jk?m)5!ei%Kl0x3It~{GJ zRg@}=r$f}FWm{H+nZDl~QZjCga^@i-Q!zsEEIn#7M~dx@cv%3C5XN=l8D&v$4no1m z*$Q9G`y$pK&Yw`BcC{CMK6~ACSZP2%yT`}-YNF1Dnhb{I^MLE1_o3GW@z8LOSbe_C zj+na=Bb^|leh+pOW?)J~DY0FL)og>+3|Fj_~v*R{*2*k;pZA}Lio5%fOt;&vLa ziKdf2yZ^8sN%7+z86Ekon>t&Yp1UpDkrDP4QQv;ZY|yQrYvM=}yB^Ujf#p(H2LZ6cSphRK!6r z*Q?$E3Lm<2bZruk#P1vWHkHKLI)r1A81UD^KEieVE9)PNRY$I<#g>ee*IX*s1; zJ9#BzdhvweJnWIo%h$uE%O}C2N-utW=?*sGXySbFEzSM#dE>?xuPvT-ZSD^~nfEh} z2rB<9&)wU#6vMlAa2nJSSdJ+9y~g;gFS50|dPuQ^V`j)zMCF-~d6_>PG2ezxCwtt8 z@#gGXPXF0kx?_81*qd}%Slylk>L3$tx{)dLQBt$S0er)AsIou|ROD;*vq`_RXh1!!WDylFY zT(M%YTt^i#k>w(ZXww2sB4)Z57Cl?5+AoBQuWuxqMRa)`ZRaJ@l;;+Rh-cj(opj7~ zo@L4eae^i8h^NblmU-?H1#Y|-hDEl^7REM3yBZ50vU@Y4IF2OQ0N}1|rA+%Mz$?fp zQ6@Gt`2_-Y-)L7#;1b90`|$MBdm^+*aGfhq__JGj^zquO`vfm6g##Y#=$jY9``~on z+om1eL1)E5`5renKMWd*f3z}lYQ0w zPn%$-gRqsLsvqsw0#Bueliz>R(&XvHdDN$25-aXr^ z-0I4|*sk>?x|1w$tR4XW8uV%QaW!YZos;$}FFP2WNM=Yj22Z@~F58}Na*Ois{^ieK zsUq?|{qpv&?Gp0b(UL9IubqlOzEBuQ12y-TfWs%HXyd9U8HJ}uaQ3Lmo|WJ4GW~}W z9J8hZWxH;zBibkR-kP-QIW2h{XNi=AnFQ3IiV!t{By~?F6o5%P}TjDnZ4BAWYRq1X+c zOy8XbB&gDhcmN<{@I>jGq6U(~svcHd+Bl>|qEl?3mc2+q_6KC#E&J8=n)-8*I_(#+j2&Y4|LXRj07OIH2Ok$+^G-*XrK49-6Tf84+HD|s$nim8_Bpu`t-CMH zUw2(Yy36acP1C-$iyFZ`anHHi0s#hz)ncgm3?}#@3>6Ljul-1SFHvV)T`%&%d)1 z?bPRVQLrR}6~Q;81oqCWqiUi?Y?$)9Y0L~o*W(ub6*aV{8e`+b6AS*~x@>Jax0O6h z(ShT>@4fWJtXE`m8Hd4V^4MxAhOb&^_i*KCe<*o&*2cdF3UHB%5=ly>G?xtQJ?B*{2lm^&6Y)R2M1AnD!mUj6UGL%Qk&5_HT7Q0rWLLO$ zKN40~p=|S~mK4R%R_L=~MA&mwg~%{p?0R+LH!^depwDJ9G4C1=q4#8QhO=2f0q69J zC}uUbz+~`kM31>x-MDAFvyuoVB{c3;>K3RAX^!4j!M)-P5wAFT3-=h93QZA>JfuzD zF*|tB?i2=$jSWeRAZjG8lp4z^fv7ymb1>;gLRC<-_$k?1BIyPCmBriM5C>d6RHehM ze}yW@e^_$or%-(ZYA#!6*(HjP{4oic)_+_}4OvasT|m7aaHyn*?;Ww`tWw2=}Jt ze8xC?*Wj>aswEVA9!8RJ+2?tV>0%VT8wi0epAm@L(iugJy zK$ZwlsZGH5fr>BgGs2Ese{#!oSJCG&Mc&b4A@u?op>fs<>duEn5EXseUuB^5^DDp&HH1{KZw)1R9ic%B^{QoCLJC}DgU z!>jsOvpVZ8Vg1jmqANOrd<|hkG9T9K8bMJea|YBo7jB|wJ=+%Zyk0GppavY6uJnat zvWtuP!(C0g+aIz5@I|zEw_^4Ik$1uw1{6`5&&BExKa1vO(pkvH0Ir$SoKQ?UuD4>R ztLL*$KKQl&W@B;_*B_~SgI;5k?!);tOc>-ppr*FK=&F4eA`dA_&|B&N746q86W^Gq za5TP%2D|42sh@~&pJ~}KeuJF8wgvIf{+}{d<2Q9?`$nMK=P6+h5BDhUx$+R+;3&De zVSnnf!F4zBtl(=&-%qZ*7Sg2V^=Yz9!<}WWC(!Updyli49BBXIzM!kOo(ax*yv#?bh5&$&d>^arMEB^@OfzZzGbzfG@pxu*4nPfK+>Pe78lezis3G$b0#X-2FwyNxYxF zGH)=d-ocTIJ?STDF;928m|OK(Zp)loTHFsaOF6|X8k$oP)(l;*FPz9rsji(1yCa-) z8{(7`kiGZ1_ofVpHD8-E6h&N+xbW$l3P-{Tj}QAz;^E;VML-ThyIyQ3;6O!+N7jA* zx7L%v#{=y+fKZQCzDh0K|5ck(lOLeXSAONWJr`D$P$h$zi_g%4^`VjbSK3}!fE^)8 zDLjn5Vmy@80F*bJQytQPkoIq&2rBqA7@LZis@1|ih3>@~3eBr{5aY^^+_{PVpg8Dc zFQOhS3)-?qnIf1f&PUG-&EXL9`ZD4T(v)!5+p_-PdFde->7Yu*9IKLr38aMBjZXQUXc+(LvP|fu8)>EDy2xUlzc0&kjhA+R`I=s+4RG zSDcwt0V3i+b=0%M3e$X}cGQl14#j|p-!;v-&U-c~tTf2bpXDdJYb)!vnYLZVxr9r- zpZP+=8g-kQ7}3Z%&{r)rwr zfYm+MZHf%0)PT$r)#po?$|zvCFz-^P9NWhb2E$z#dl>{CuLgc8xNc!+am#A@cLH2y zwDP*)(IR=0lnc{Zd)+&`o{ENugX*sYu`TY>teEx7K1Yn@Qa#q1b=x(8p{ctqTUmh- z*R-I4wCsd>o&ev~(liW%Vs61$=v0i3E&yp=pqN*SBU?K?+8Mwgt!MyDT=bT!?;_o+>3&^4S@I(0JdP`)-H1vRsy@mv(dAYIU`(EruN10wd$gvt3bmIt2DRfgsScT#t zpIYW94n^r~O4;=!&)WoYG;ls_4LLdjNQBlVlmpQt^Lp_Xc+2OxBK=109EPejf-2D# z>ER4?Cqr^OH;Cxa3bXUEYWpcT9svrIBW%x$2R}$J&Wh1}S%hgd{QfiZxM(hd&HP^e zFn7p{ER8dAsBdBiA-^TVN$wlcEl%~r@bI0)XL8pPPtT|OCz;+i34^BYPTMkg|-8rLda=enOZ2C{3&V` zIF$oIGynWQfZ24K??j)Uon(SMX{l2uUiDRXdz$3nQ!EblnK=Yz0DpghZIi~Nd`R%@xk`W*aq1JfzcBew*U{7e^4Y{~ zqs>cLFMDd5`^T?Xnh{;u_GDyEOv@;v;nVu3t&Q6v!IuTp<-#iG_x7tF00gUC{(MLB z)>+yEP&gQag@%?elhj>P*)*wphl{i6dGQ*iC)D;1?jdL`<<tjP~U}*dTx6gQ`hWPR`m!7j%wFkc92Q; zyl7r795j9oI}zgZ5Hd{dBRG(rY~3K7`WFP+klXbqbO(G)+7(!xkKiGbNMq#Di@#i> z{(szsznR(b`@aZR{AACno*~PPL?HB$KRwyh+pD%5$R2a1yQW;f_VVM?aN&4}MOM&s(UzGVU16^XaRRpwxMJ+E8`5Ic6jHzQt4CzAQ8?0zGs$ zR~BK(T_-E_cv5ZeB-}UCwe0$xd+QHoyXo`RGhPn1l;oVg-^qE|TVpSCf&l;jT z|7BsG>!M)uy`V_l0mq)f6n<52{hsIO*-zHHr=C&A)sNQ5iLT?-jf)v5B<}{9RBSGj zd6P7YjaCp6!q6l*hkvK@2GncKssN}3`zO3J)+0oT`r&;?86{dsT-D16KBXPN_WfLF z2Ha|ADZVBC(GE4&P>R_H0Hs8bcsBQOaSNWDMQ>G@dvz86SoHb?yg@(azsu~_SSPjr1iBjo6gxd>G$$%GSWj!1F!)UL!?@!7#Zvn< zrSB34{-SY$7W|I$?S3boV$Ht}zJ3|G9^wShFTIIV8~vJp?>{^4|H73n;em~k&{xJ? zltmSYg%Ci;E}E3TzydPR{0}i&IlQb-;#JS$s7?q7_ddFiMwFdbuesHIhlU>IbFQyz zGn3R{BwsxaJ^u5zWI`CW5vq8t(j}sGX(jO2aCQEl&8f&>dl%+W3bK9MKP;HaDJ_Ng z1{vXbAE~2u>3oOpo}J$=>-2l^t`YV2Oa@g{A;au}Z(@^sCdmWZD;`z<|9Ajaj3v>R zM-X7E4+iJYJ`+|dQ^la-4(p6sHJn+jjj5Xsg%j&$>jL6?ww8h zjmdb*)PvQjqltqgVPrfkiyM&w?2s#gDtdU!N9lRyx_Uo1&^zLL`=Rd%cc!``2Kh1HeQg3@&NANws=G6tw}h|aQ=MkM@;9prA8@62Mo6=Bydt(Qreu=&IUrub zWLGy$vr*I|r-XA2jLVr0`hfkN%yjgM&vAq2zy@?=Aie!|YQv~`q-F-BzYeR(>(-Ep zsa4NE0@TGw6VQ*~NvR3y$1Gs`o_;jOyX;?ZiHV#kGf^A^)+!VD&st;n=u@QJ--7+< zvSGs^Xvsj%`Ivzn^VxCMFLRq^AWtKQM=g|w?=X-WSkL5R`JV||^s=yr3mDb?J!fYi zN44Nu^zokvF~u-CEvKQn2xM2-fLlfibAnz=O>_3qstBePa4--S7P+v#RudQuy$ZbH zh|oLFeaTwybYR(UT%Nn)lQ%|s)JrGjCisC#I={OM7)J?7?il<2^YNvGdf@3N1t$Ev zWNSA!1h*5AxxRdL+=2&k%tO+NUi0U((&fa3p+_&pXMV*D z#JPSEc+nC@Yo#(95INH4s`qfBdhdzttVV&YgJ`XmNvZp9%%Wgnphs(!6p^%j_wC&N z@{c{u2Cc!;-aA%tAM^@YJ$zCS?*b{7lKp0u4${}odn9Y0^I=f9sRO~#lByO1lNt6n zIN{Z+wH0S9f`Yx)(&8C#r3C zI6f2JegFvs)Ke31TLwW<*eliRhg&mBG72!;pw<=Okia<$K0vvP}R)OZ5l;G5;_q;mATz;X- z92H1hjjCC9Ql1Cj%O}mrCQGIhXp(kj6O+|2&@=&^)kzrP1k~Jj0O-v$ZhU(S{raw= zNf{hX5s`O4)oU9S2k+v-^kWjnuKiiAO0-fO3Y=6bsB62A7;~s-8FBt(JV7JneQHq4 zp`rbKJlR<@C*WTBTH&~Z7A!hhaadEbLhRI@$gs{Wj9HZwzI&%nGiG~Y%lhfD{w*v{ z+4wzXX(>_X;p_glVVlDX-0c05{w)I=534R_em}z}H-+rkU7slsSKElqajt2VdRz@( z-txLr^h`7ZF5`P{V0smtf$|2!rkGDM3)*rBdVjUqxpV%T3*(qs<8$W0?gvR_4bM?c z&A%J`ehQc>0|5hMq=KnnRL^N$0R0n&dVntd-Inm8 zZI@ZX5nd!qx{?M@aC)~rKa}LKqg}v_nPTlaNO!$gMnfUUhNt+d_u1t_Nv{B59DxTP zMhh4*nRdizIYg7BDoaP(;20bUcn2QOMTCa68i28Rt70DQWH<38eb}vSUh+2@XZ!2@ z6D4hXz_;@FbJ6w!oNBZz5+SN{KS_b2XDzF+?^o*_{vo6JKtTgD7UnaRc`^AsXv z9!i8v8B*9XZBrys;%#)_N^WDldx91Unik7d_EM_X#Su`BM@pW5UZ^$hpsdujqd775+E?=v3y(%;x8M zv%~tWjkzn}bZS{J3?7c#NDKt$<+8KZ8|emdbM=Q>DGet~Xa)7v-$=3A>gB1bp7T?j z=}FRkSOLA_BEe%W6g7iPeDUi>_YCs_NB3g6^s9hSC$}JJE3e@+YZoDZH17Swl~eM! zcN^SXgfV@OLt@XDev3?fZo0@z7%%9bSQzfL47;e);O!Qu`f4x!5XGTaKkIo3)GP~+ zfe%J=DPgV<@?Q1MH;Q>0NDvd|o<_ILbi@ygypBaVO53+aGC5Ht|EQbyZog3$7u@l9 z`{fb;uBh7fv?6CSAP5q(X@Am5<%8uW)ZEH_kIq7fg>14p371lXIy}ttRR_(~lQw<~ zSAHLFtnYU{+NP=dxG9;z_-;_7E}^-dyU$H1+vOgYb2QY8mol~+gT`s$q+QV|pn=Jh7$mUR zs%>>9NMAAPmpEk;F&BrqvY+M$sh#VFCbWE>U3Od*0b(-v zgvhx!VaFF2-f;Kx#_$qcw4sV((HV`I=F{VowmTYl8z99L9M{XtqQRPQF#-iGj{(ci zc6p%`oGQM-Z>wY^&9JrJfF{1ey%4cOtdHv_umBn=a1@zYwg!ud{F-@q1Pj))XI(%|K z;*Z$O8jo#fhUU)eM>kH3oi?F=k)Pz~uNVEpm{0%rOxa>L|6M-kw=-_XD!QD#QG86Q zCMiT0H4tB!5(*UY(fc#1pK$cdc?W1IvQLSXoDL z^vbpB!B1|t2g_!9Lpx656W-@@v+(IZzn-evL6zBZxnf!Du$e?yoV?eN*Hxo^QMe*$Wbvy5IK2{rd8NDtlE^H@ACh=#)3U|+*<(mJ+GCTD7bT~y2> zv3)mVP;}`*jpUW5LdTd0GERv&`-QAU`T`zya3e+nB#eCq&hVOv)g)|a&$!~X>9D<7GFTROXC6lGKwwnBe4u;esY zBV=SF8MJe?>Ai*urmmZOgc8)|A5WuLoUHu0>S&({)iYD{IQqVtaoxS=npdcn3fjd8 zO+QL$xW$w<6V$&AnzP{P98p#VZTByf|Bc&85u){R={X$vvw{3&#`dxNzSD|5_>E3F;}k^H#Lw z5+h6H*5<0(uLP{huJP53Dgm3^asRvuPAOJ3uJv6Raizdv6%-Wq6@GqW%*Uhh^O6YO zzi`b}sW^mya-88rxsCdB5=_s#^r;&zTo}+xPq%f<@6n$P#~PJhmDTg98qmg5%A>^6 zsx`)9${c$+Ju-BTh?|~Nu73ANC+FG?!SpI~HJirnTpdnLVQwvUjyq2!TEaKwCkHov z5BWP&mOO66_uL{wt96nxzAPZYO0?a!xVx!TnC&xhls6T;vcG>$gv>ryh)Y=M&F$l! z5q@+y{`_Im_;zf^RK7d*nx95d*qhOA%as|nf~NW6h%CDrqF=M)v>Sh32|X?M{TVQG zW}Q86>1MzuJK5G;bMzGwm9dk3?bBCd7;E)H4dqD8=cG$Hi7II)e}DQxvwq{ZEI(m? z&&R3i(yO;GqBmS#CgjeB<)z!sjcIEq+0Udpa@n8-&hbAJ^IyU~i0I~W&NPY+PA<#i zBIeiDLz%q1#3xg`2BxF(<>9v!vPswWhTaeTnstzA_>1kZNTbGlaMrui;PZ#TlyO)NY*Hl+U<(vj4WVcm3g5ae@TCXrP9%X}2ab?qh_b zpFnVNe|b(^dtI7(0p&B(%9IO-UdUx)Ro0tCS8KOse#?sS)O_;XtFJ1pYw=ZUb|wF{ zAR9SBYCIb)<$IN`@hrh~R2~0Oz0-SE7ah{pVj&+C<$v}%9sV5<67sB@g-R$ICY<=If2-nBPWbfB;Ug={p z!Y#ITBtKE7v-jl}L6=`&PSs4X#ArUC4vTB|3MtG~{u@#7`Pzzfwq5GAXS>Rr=Y(ZY zY@vp#mBIqg+;gtaRp#38h~14b=Zf*O_*1j|sYk(L#jcV2$!Vgdz>SEK3xYzDWn+B*9K70N|MHlfh zG1DW4M*SwXvf0_#K^JqnJ5R;+r0bG!bV2^gmDf7I9l{VQyxg{j75PVsAH?V`ux!a^ zM1JkRXpepq*B)wqsqn`$8;qa7`DI&lF140@)GsQV8Mmd}=K;^0b~ny`xZGeOOz~YU zXvsp>ap$s0-KCtt)H`HUE=-1`*?AJSeoG= zvqZZ*>1_0$U^ju$>5#v+6_;k}nc|+2V} z{f@z%(hOfZwU>@jH!b^Jjm7OVM#|d4ozY*nGi^H)UI8@l0chSVMc)&+!hB1XfM~@m zqFUxg9wa6?K-FT-Cw;UM*XpO9X55iu+NX$UPr#ueRTOie^?Zoi*B2jXGBZsQ+9zYH zqJ5|wd?K_+4R}`n9=EtO^D($^`OkOFAuoGY_P=ZI&JZ%53q)V7&YPMXJlnov<-4A& zb41oj>+RZ8VG(C-VGN;q^kMTH*X5gYpICT}#D&S;x!g@I&mMhR$)lZiVl;`vuupP5 zj2@T9mtu#fdnH@7NJ;km@zZ-%ZZQ?c64x2}Y}KM2N28vXN8@bPzP%^N`gysGHw?2+ zK#)HRsD{9kq{Zkx-HNGvyL|S8$u*e_(nuxPyy=$LE<%~uM?%-g97_Ko87traAsIbu zXr4)DyvKRD)%N2AT*ooewNm8M3e+vgYl~M-47q7zHR&@={lAXWXRnoK_zaZ zorwLW9>sTMZ_K!DAp2^%;;)5y^GLHkvbHVrmh~qC{G%qt$~2cBcr4VlbGrl2bUOeI zh>@D^$S)mi*AaIZEVedqloPSQK!pO1skcpcexDG&DuW4!`bva5390bYNRu*Dn}S3F zQO7>+cgdnkX}A9Dc)EP9rGdqHo^iV0UWq*cr=D{qqi0|A#Z$dBfA=N)c~ zk=w!9@?1ypWpF`7sE!Fv@+#mI0Fg|A^IYq>Ku>m@JrbC)PFcOamyEcMU9l_+*s9)W z;qwV7MUgD56UF(jq3+YspKtDZ+wVH~2(PiC%4iNm#qT1T$!Lw{13$r6OJ1ANc7U^3K|w9 zjEJ0uGQC>=ZL!tao|yXEOHx9F@yFF%ganHbSj1b=xSB_#xFAwoGa)D&EHg?4cO{x9SZ03KN6>W=o!d-&_~^6h*f?>I1f0+Hp)#vqKkJv4SHE5o-|z&w zB3zo3I3SyaSN%5TPfoSqv-4^OpXt7tn=4Adz32Rj=T;zw|LD<(H{n~^qmgr8C4t4f zm!ELM;MJu+v4_C*P>jK$qx!fkesp(gb|FJGp9=rs{C4K6t=R4KbyQK@NL8yF=ORh;+d=A$4Rzvw2 z)F~qPZb}uz&qw+WGCU^*xM=8jI+qv~z z)qNu}{#j|WL$2C`(?-L^!EgHWUKo-JZ?Y5BV|`22A3F7IyOt7ag5e-Ugr7!M`w#_m zCCi>w?vaNvx&CBvP=(B_5&7~1qO%bILMEV(X;&6~Ty7A8sf!i!S3xC26op)Ki zT7=mL9R2QpK>$ae*={y&?R2w_NeFs~I(_8*0c>M#Q!R=>Q5-9A-87O_5(U8EYvA=; z0UClS0Ii{*8wI#RrdZB%*NIjDN)gpH1ts>c;d;LZCPC<3CH(rhcW)(+IyXkIXQid$ zU_3IaAUFxBe?Tif3yd4Cvh|+{OeJ5Qwa5>T3-O``<-PHFv_lFrT0w}GJ<1o~jhg`z z=)-eYi^o!)M+&N?wJ(6`Mp#g7JNZ2XHyHM4UVZ;IE;+QGf2GFfh|H z0hQm3oCTOvCtHQetloPwAP0A*LNbOX$NH;rE&F6Ycgt^C6skobWHe2XBFielnJE2S&I zfnavGtk69W+X&FLagm^*Kc7C8f+OH8@HU`RI;cBCrTba|uA)&xC~HK4W$wpVJwse> zLgY0d>l{cJ1f!78Btbk5oey)l?0m|0zVOHD&f@clDF`xsAFF?kdIz`CJz_1qM$!Yc zAI(Q-V)iR~xPSGYawkq`Z)aMeM19a`rj6lP$;FOT#D3}E!sxAin8a(Lo?!LRX{=&0 zY5N~%ndDUG-ElwrL}*_{@fNTb$rU1?`poNVy6+=+{rEIgMIgLidNM7pCMoFe%ekiXP5` z&r%V!nH1{2?!rpRt;;spb(Rnan!&b`iZm)I{{B5}V>U9FzVjS5Gy|Pco{{R`MuYSY4oE{w4xhW+ZnB`~Q;{6#(I zJj<&(T=P3IJkj0VY*yegAQ+Hetu!EOhi-1YYqNAz`Jd7JNnd4xWFYU^oD2#QHkI9-wW>S+bM z$8kwapKL%=-6Q0t85pu|JUFrh+MAy>;{MwQUu0wJE~82}PX;4beF1bJ_*uxqn0GaR zosoymg?xWP;xIysu#B|xBt+xq>KHJ{C?ao)V^&}CF0VC{bH!cXH-tc@-6>;(UQsOP z^)?>TMUPF}--EzP0*)(EsU~<|&L`zz+RAUK^BgM2;n( zDEZ((1Rui0y$L4u;GV42H-v+62D6r@%Mb}S)|=jkxrkggu?7~U?teHa1s4sHOitAH zva{jNZ=;7&yo5T-9PE5Z@6-K{%CQ9%JwAA@7JQhR4E2EkR*q`2U<4`d6dlo?EKD9wrjVvtok;NGXL0&Vxm6 zxfTtr3Z(p(OI)4|exIOI&)L&3K~uyw2f`CssSb8eh0F3N-mKBLy0^AmmYD*WU=AnX zqRLpcrZuzI-gzIUFit!qf4qp1f*-WVNRm^7^0_O_UbuhDTU0HcsCDDog~-?K0{7jKw3};ry==Y>Nu))} zutkFrr~UR%vk}Zr;j|}bHM37YtI$A+oQCHnpS^K#7K~G1x}CinRujC0 zpReFEe!Je{6vlXDoOGI-_mOcH!FhL#y1-n*kbv8|_&QZ(>(`1Cg4e?M_#XW@wm-gy zLA!EL(vDke?foG16kEr@4wBdwb2&aJksM@Dz1PM9x&E3PNLe|YRq^LsS*ga{K~BGX z`Cs4p?h?Fnd?+RFEAq~_|Ce{d*c-~vYIecdydQBs>gUSz0JkNEcvq%O@7yp0qMSs8 zL5_W_?H?uSqsNY&bY&i!ZYxx4Rww=CW0~tvA&hLC z3fle0`od%T!#@0CgA0g(>;JYKV7)}8Ihw*XHkAn9R`nq2r)stdUyevQ$In#m$Wz*~0g z`5sh0WCP*V{07)DR(reKxOABpql<|W2)h=*ZEp2N?MI(rRaAJVKKb;2XP3XKNo<5} z?jaFSj=!^ir8on_I=;xLm>HHsJR;x#H_?8{LLfet2C5V8XZF0-dg&(%Pm7u~PJd6f~nkeot^@JwG6s6b+g2-sDvT~U0DUQhu%EX1b85YV+X zMcL$8A79wLXWpm;;ILp70F7usVy^+nVO;N39B18;9ssOe$ z@4N1>@dsGlbb!X!Wvotos7m_^PoG!X^;%roF@`gM=$(EoXdxE;Ma>2 zfNHm#Mx5K9ha`x4eAlt*NoNCixw5q$^Z4q8Gh$x5BV$^ZOjfl^?X~Mh*{^C7b5F9s zd7ijwUwokKztFr<2P2?*9HfG%g zG#f^@LhFAS5nMVs5^Y)ILmtK+78xGgnd1)WI=Aa-_b%hR>V5 z=w1oeKtmoIv)#5~fq`znwepOOdcpJ~oKQ;pM8I!NTa;=fV`k?=mn;p}#Eqy5tC*tH z$6~feZ%i~5?+7{b+iK<%h0x_EXohkBE(pWkfSb3Eqho&cz(~3YtsMKrZ#01Afm~R( zNOw)qhYP2F7F7&ufz+(@s&eFy=|I|0i9{(u&^DS?^5f4U@T|+1y7~3BmDh=hiDRMW zLj=>8^u@zpw<1F7dHf{RFtyzO4ozA5Er(!~e53qUaiRz2=0>mkTCSuh-IzTs= znA~Z4Y5S^IYPDLnhQ-M*iF~E9ewzj?b2@0*tx)R@MDQjB;XNVPfnA!FL8}p z`QX<{6_S`Fi2_H`#NC-?LXfeWA%v%9mv;baQ~27Y!F_NPlVFmzecFQN@6~>LU-UV#DKrx%PK0cyno$B^mxn+fv@u+ z6<+C@B^YzC?k7Q3Eq`7v`IrFSL4^i2`jZNW1dRA7?gAB*-;FWf0&Vns#8&CA=5 zanvVc;M2aO0>{9-Usi&r$WuzyYanYthFtvKLGMOn)N@R@+PuI;VMGMQfyT=3VB%m0 zlCT31x=wCHuMQg(26GNz^zceS=0m9k_RR93lxpxuDpjHvdB8MbhMnw1zur7pc^$MQ znGE7Y&=d(KfZQF2iTx4z{zDAe7RJZ$s!1X-=e1q6e`a4%xph5EHc}ZLT;yFQey}-U zCB_k*W%v)e`3zLh3+9qr&dP#cc|@|fL_|&yD0sWJU9ZfQ8OI&pzPH6b{rf?N{Ff-I zfE&xVLNZt~DVFcN+Pa^#b>ER&Z}zt@{VWESfmbpI8!A899`>@RYPTYb^d66bWFG4p z@<}eDJ-M$-`mTF&;!qpYaoad5j9i3P4Ik;?u=0>SaL#A#A-ijxPyhSWpMez1F(-Dp zNac@j`+V=7&HRGtQ@Z-*+JP~SYo;Tu<>{ldy2ge4qPY~L>JR_tAA$#hJ`DeSPcK@t z@4Xjk!=(Q(R)!r+ng{aZ&bciQc_2Gp#tX};Owx7Z!0$E=ft6!+vk^u%3G6;zf>8v| z?|rf6wnTiquKNjW`}(LKBQbR(6|r8;eQAhuKAz8wLc99_@c@K^3emYT>)kR?$!QTB!NjVU%24HyuWIP zC`4#GME8$5x8*tbShn)L#r*>bpSA;mL!Ji0sR4tWoGf!Z7$kSI26x-PRp^CfkD{lk z3EMxEL8O3f92|O-hzP86aLAjygLRHQbQa|Q-~lS20?wIYhu9CsgtFv`v)+FZuDKaT zPDV|gs`78j?+}l4|6Tuc!UsO%|K}#vPTr=Fz^i*MiqPDw0Cv5ycS*yUEcV`4?(L@= zRx)jO+pD3c$G|x|9~4FMeUM#2!ZqoG6S5lzYn=H;3!lT9s(&A+O=nwotL>{(#+q#|oV7H8u4a5 z04^uky7J#Z;miR5!oii+2zQSNEqpU2>ut>eUh|7>|FKJCveKYfExqBLZ^FW<4lb!> zd-$h%j(kkuCg5(($uOPP$YWRjb3h^vVZ_!IVvjV8Qn!^#+8ju4gAz=Ot-EO7SA}1h zq2U6eNc|!_(sV}}B0Tp2zqJAijLl5|*H1viHMHR>Gb!JT(Zy}=M(0dCq! z=#GR$B9NvoNJ{bI=<_!C|0FNcrDxxdcnm#vj!`k6Yp!*hJ|Sd!4wAbMLjbG=@=px| zXX;ob-7O)tQ5}bLha9WF%>~vS672^DLM!>6q&bgwtca0x5}G}=+5yupuSJs#67Up@ zMn8Zee420XQbLd}l0XEqx%L%O3uei>u1FH+ zf3@v?%mncqMF?yAGjrS)c-S-?4Pl46E3BobiT*`ET`2!)F;cjEtA2(fjMj30*7Y%w zY*HT0U<>vZ7zzNOPm9cshX8(HXgHDuesiu5;{hBG6bM@YI-wmbZ%c4ajbFH9=%G1c ziKN>UDexSy75PJ&=AGXX)Esg}%?~`(?*Q+aK)T$Wf|5dLdxO$5}7~bQpEm1d}vOldWaU0KruBHj}L^- z5ua8RDmD^?uFykj@$*mYx;(4!yI5b;X)Vgp1bxC;LRI@9^EV{HE6kcR2*BOF|l~xqoAzP6aQ+%~dQbLCr1`4o$bFpl?$mo2;t8vJF{Vd0|9sdhNdZZERBa!g%3Im9eBC)s$q(FpC&zju^FZJ+y!`3&T ztWG(zjaE5k4>Er1h*!PdT?ySxkt~&oJ6miv4=)p1;hY!z$j}gH6R`|JDRcyMRvG7? zFN*TC8F7T%c0`EIxsIDvD|e?!TxUiao=UtYI2P-rv!Y+4^N=395co431r0^-q?zNw z&W++S>qUPR~3t?sL`#6sOX5cQB>v?Ff7Q)tL-F{u5gT=zJ<0e ze!8wbD4C~~#$0i>*oAtAx2tB>%3Z4PzFhOr$u6*tTss!ivMIsf& z6Gx);7utq0{BZd7+3%H02ewKms1}Ht1;kbaTcOC09m-fnfcsmc0AfXsLgguamzZhgBJ4@f~d*B+4R0o^vV|$tTKb!2(vsvQKJl0iV z5s_GpL%(m)9c~5evE$ysz261n#{BiHIZK53Jt&iHeo0U<|CI9E|>BDVM;u)?Ix6!kHC= zpy}P_?<$3qECCLL-R61xBRmXwIc4(OgTP{JkTfjp&ky}xLKr=k(}fwz_$uFf!}7B5 zsg0bDf8lSO0%EnK1&8XgLi8*0y$*Pql)BegqQJm%Ou&_~{oBG5WS~VIczxxif>9mM z(_tj;tg%5}@ZH5CZ=Qdu)jJI)bk4nzBMk<=Qzl_^KLMu{dOu1GacdMw-q`&!w}as8 zdgyJfWon{Ej2JI(`}oba(#C!ks1Hg9L0T8INYeUeW8c`9x-n*j2II5vVZB>#WeB7i zI2hdPC*}K~0z}Ngh*AT>kE+}M2f{20yx&R?5~ewEB8ZYn?B11i2*VrD`+s?T|EGa# zfioW=?T5O-~_ApTU=F)_1@UnVUXT=KF7RpJ1iVlhu|-dtK$k=#?~hEixm`7y!G@ z1TE|^RK^K;FC|BjYL9?lUydZ^SJ|S$B6 z@uA?LpVQzS`Uei6$Tfpf+COOU5=JKYI5Demzruw{hV+9}i|6690-RY4I$b_J3I+!+ zv@W=dWI;%#c`i@B3TKm+0Q)Gjk%mVS9v-Jqo)U^2Xe{Fp`M>d#1EK+TaJQcl_bOOg z-m_`94Md?qhazMSd;tCf$j<Kdx{b_EnZw z#Vk}_Z3bF3+yw+Z-?6C1WeOHydHIV{1DF|(eL0G7gDR=bGzXIq0Le;xRW+}OuX3^( z7S;w4^}WmAbzs_`B1(gidJ;1!itcd}?q))epq;>V1Ogbj&!A5t2RS9BfxbD?j!XRg zfGF(?&jlm#x1P{jA^fC3(k#hTHuHKC4$(DVxOF%V zT0FaA9S;sv*u%8`l%P0VN>(%I+h%Xl3fnHb29?Xo_~KM3C`J_l0yq(za}bF{v>+LTEA3rEnZXPTM~ynr!H#5O?=GGSJ^_2hih?I1 zNW``q@>J`yA3^+-5{6W=Vd0rED3>EJgMAtSwukjef9Xvb7&=lXOU#Y9JEqdN7gdRVgj5BDh; zG#Tp=u+zxi9?{Ig?i`XTdiTIJvk zy&ehthWrDokYfzW=h*xL911Si@dl6$`ZE?yMcqD-{)iOQhL=D|BP&G2?n8SgGyuxp zyT3#MqRrZiVLHnL>6oRRkPa*{-gKw1)0U@ijU)^;=hIpgO!^MsN;UksHy5fevhWd% z!qLAcg1h1@g7zMBmLga`9@f2)Ck(MpbT{)ohdl)2lp+O5Ejbh?XYa;=Zf{dk! zmmFWrZ*ToHhdfxarG_iI$6%qS3yr zox7iMN(idnU%^4<-quAbOkZueRaYdSvW^YOr_gx1FMg{t_|7w(oD+Y+%;aC=MQuZ; z@o7loQa_4$;}GAzToQllt9Zx7pF`zJiF{w7V1l{cYw;qKTqYWKesV_|_JV55#rj%( zhV11-DTc8@6!60LrwMNLt>UlRD~xD4Vgi47h4B(@aM=(AASbQaQk9#K$Zx186ac9^ zI~Emp#USstiXNKL*mplJ*LFQA>A(J+(1{JbJqCGFU|y@pA?d)j;BFbHJ;T`|EnmUm z+TC62nHNtPdBmg1te(Tr3e!6lYjT((IcOhExN9}P#skTT?8FkyJuoIJ#$_mL0+-}1 zg#H$V9u{R5`3UM}-Rs2d?JSg9*`eRm{RE9oqn<_FsiCg3COY=S^$2p5v^@k*UVkW8<0?Oxno5t5KOUimLDM@ z{NqLT3TnN)w9ao5e0n)SGA<^AN)eMC>w{2r%n7$fI1N`Q>JmY7*vgPwPb~3^IYY09 z(Qw04=nssGJr(>&Lcm0OxXd1`{!PAWGOPohM;9$bqvCa!^fTb29xPTlhjq|g$~Nt^ z2dLxM({LQ=k5(1MB#fEZ?&Oo(L5L^uSI4xJcXAA9Ie$^>2Wri<@S*f4%ncgI1pTte zvM=Q{+`g^~2_L6Vlxd)r!86S1`LJN&2A&d)w3iDeYSm1YaKh(v8{~>@ltyBF5$Jk4 z+=PfC`7WY6t)TENz5KM3NFBD5WBq!VAjOm-1f9V-(m7|_nJ;r*Z||Y17jh$9xc&37 zX;=Fje;C5I2TWHqh|@ujt&<_8l5v9qXpO0+So-%uKqmazJ{GCqwA-D?usse&~s(Ca;C2 zmp3aNfZ5{FI)4~cm5ubIO5HqZM}75y<7oYKm+#qF%w;Ey;l6>~np$^4?}6PZ)K+Rf zCjbR(*~qaHLc1KN*afhVJB%2-BN&|?ddqe9s zHq7e#)aTEVYtEy%@ekfUC0-ul|;K&IvOP*+>AV2OU$z zQv=lYOz*A8g*ry*0I5(wo3eDb#2hwl4?#|A9U2wH{0v?)OYcGxz4UA8Q?WCEc4fzZ05^osWpWPYBWnA<_CW)xkX}3v#to zZl}p@X#+p0=iqEs&*5XamHjDAJ`jhP`p3L18Gl>sy!8Xc7x&zzQ!CPB+^Ay`3K*Zw zmG)YzD8Nm=XCwWyy-OCte zFM+6&XT7+rqYe0J`BIwCrNmiv?~NZd9!`+esq-Q-aMB~Upks|j4XkC_Eo8M@2nqnt zM}Bv?Ejr|zgz{J6qgETA@BAtlzRlR!Af!In4%9d{=X1y3apbhNY^3!z?$GUeeLp(5 zCrS)=CKi{;b**GDJ4sy>NzDBOc*IHC@WNAjZDnn=HKVdwsnfJe^3A8hxrz#B z7aTreDYyIgZFcL49sPo6e$8XqJqctt%E^61F?yFD3r3PYMv(cV4@I@3HIRB5=XasM z-3lx0d#KfOIF29kN+W%|Z>L@YJJrEQ3(f)L-F$!~U=Q#bFQ%-6Slh#Bm?W}FulTeqQ{(N2MbEIs0kkQ4| zV~7u*P*KqI>G<)VG8aFSmX~kN-yBLGcI?7xjk5;Ty?}lQqu&bo`F{^T?e_TSq)(Zq zI-sY2&Gr^Y3Tok}BHrWSDFCMt^=)o%pDa*~vw<6vs{d-BYda*hfYRO4ZQhIj=h2(V z>Oa7$4@0Aq7Ptu$6;!z6)8pEeM!TPk*-x)54wn3?HHfxE@x}a!eecPg`s>@qm1_2i z*_JwW-ZnBpBk4N1y;;6KJGEdaS}hQd;mn|AGU3r<^zXNqY+`vqLq#m71hwox+S#5~ zvJbmai*0Q5xds-@RVwq(=$W+FQe4Z#W*xHWPLvutD{LOcg6T7KZ-|Ce@X0uAowWFy zKX#R*ZO6O6q=X8bf;xbshgI?_)p_*xa|}smt%;#K9x0};P0@0L+fod<_>O24V$~%o z!1LZDyMH>~7cNad*Ky{^GlbRgYPR6uzp@tn4K2g&s9%U)$jJ_dfN3*OIWV1v(jR{$ z^yIT+iqSK@)}xpzzK3hi;yDrPAYvukBtrYVYcEV+PK9TM{N- z!3K^4fky26LIN&?j3>_SzsAwbLuhg#S@4QekU3P5f5%@vCw}I!R2piI?o7G{aUJ*~ z^AY`i_jS>YZKgescnQ9JHedvBkg|R<+*XZgoVe5oJP#;t9hRSz^`em}IN^H))ZF3r zqPwK85olrV16$uWw1NZ`KD zO%dif3HD7S3sSmZd7ao4BR2E1i1TZ&O2;Tl()AsW|Jbb*SzP&aE4IepvGcX1NUf@r4M+l32&g-0IJ51^J*R3rluHB#Uu2HZ)p z5If>!N2SevM~Eg;qX|BXZ*y^);yYPJU5;di4(TN~TeSUtZDe_<>74SJI=(gXx>)v?SSuAYfn4tEc~M#v=4YfJHn}Mq`eFZLVGY ztyki@xD0<&CsxaBg6V!&;FCwKQ)c z{NKEi-xKzdA}+cDEfH&fuk`zR4}m-&V4eag$O8`>RCL}Vi~j!w@>|i90{9}m+z8V( z$Py;Sn~B^w)(WNnD}~aNgVnzuaaVk8?tGSV{m|ZvEmDLt;J=mge`nV~(_$VxojI%g z2>V^MoSoWLI^=Eq?Pm*4HGK3;X!EP*>kv|@;ooz=s?Vg^b8=4}0A13<+i{Qi$o|=SQve3t+++q$l^!<%xSbmQAhBpg;n;d!jvixTZ4S%XbYB#ekPlf-R zyXxo#FMfPF?ZTJs{)fE#h4&N|Xy@c=%Dy%-{_N8WI$wYDPfTWKGMqi| z9xtq+6jwu`nGUr*`bEHDbw#8F&p<10&KkkZHziQjD3=j>t8K4Yn;{e%UguJf-X13) zp64>hJTH?ig!&|9_fC)i?)EE)fsv=kt$(rz)R+oQ7C&s5J#$G@H$ZC7ct_Lk7(#+|g23hO6H6h$&oT+22B@z(;y%+J z4EVVn4}YJ~{sVlXVku@ii7nn+k6|JM>J8Y#n63^aGP zr^~ZlYl#dk^65wW%wy-VZSu(v%p!Qb*sicp)hD+0q-tj?4O2L2+Pv8Lt5nQNvN(+G zz(T42i7y^T>Ny<~8ZL4awYX+r2M}^Ktv=-ccAFEIa;99CR&wd4MS@x{$=kxOZ`(0{ zI|tTF2Q7U+IQa)Y6GrGAQrfFb^eo33Nalr|-Y`__NhjZbhu!n~emiopj&U}|LMbkR zLZ{MG_uNktdez$&3aKdT-Uf@q?MJ>nTH54#HfPrUk1<0WzS)L)i6464xUDm-_;d+xZRfJ~JVVTYGDkS}R?KLUI&^}nbBIDm}gokq??)98>J zihMsK9xROHAwS8^f!~Z^z#WxHt47!>d?ryfb*Z5FM&;8;s_LnYDi8fZwUTLeB#A!cno}|mMOJSnhUeX3>-}vxugYK zI!*i#b~=v&5t`w(+z@}u-%}!m*c;;wOcig&fcTB!XlnR02;8YF&(AydkphBSV~@rt zN!oVO*|f(Jg^*Fbu3u_;U{q|H38}Ept~N^9RE7ZM)DuYca4INj&n0&NQ)d}El5V51 zR)c^;{e!4!!K1%Q2mPjN0e9Dp^&stN4Ig_z>tTL?lO<%vomsB}{ zAI|8@?}nl>i)XD{OW1K48xt=p)X2)$+8?Q-ZT;rI+8^OFSiBU|Mo612`@2n7l-xAh zG_>0}oXYrl)i2WcGjpypLvt5Hsg9W2WpL6?PPlw8`u6+N`;C+ApYIfPnyfmen z?GkY&6SaVALw9C5x*AxiYmiA9J68g@e%?!Jj=iO-F-Y^Cf(QYSJmgBbLXN@aTtP)i z1!NUCUC;Fw>a$D8FY5DxaAWg@al;^ ztUE6@@=AO^Luy)^6nI{h`M;?oYTOyP6$?f!$*_m2#NdmqEu{p%=L}8X4YmHfba@Zou=jH;F_+hWjrtxmcQQ z(bu!nAa5WWVi^cb-S`Z0ma_m6=eGtj+7~KN9-|ULHVRp4mPY&ccGoR*n$_3EF_SdM zD>k!(U1!My%^M4oj<8MK)*WM@N**R1Fr~x)&?|kZgQ6T_eZ;X29llnD>gA7=g$MpjXedk0H0^1Leu{`!GgKy>rs_g@U=l)RpQp zAox0v)}oOi$7WKw*VbLbQvp!yGlTp%9z0zzxYJ6lNUn<0bUM`cZlh(sAfj$?VTch4 znCQTc{-wINcDlsMyPo6Y9fQ|7D>~ICR#nsmcOg@N@kSLOf($5$_89VHJ#>bwPbPi9 zMC11HK0B=&4{;_hFXVN_gwx8?&%96;dk#g}V$WYrFEis}xzB{wq=&u!dMp3PvQ+od z^I|+5#p1cFP~VciRmb`t{a0*5*gO0?4Mu7(ZByHo4~@P3pNt%SKN@C&(YtU5a_)zq z2+DNr7tk#hj+tPN@lBnF<`LK!b~ecQQB9S&u2W|DN~gY3N^VstuWGRH@^KL5R$zV{ zAd^DJR0JQ#^o?f6Z6I;GAW1OLz#;}9X>zC6d`KMpqJp__+HDmdEBEreONg0#g5&YT1kXkq!sI<_dsa{pf7L zfmvJwanKyKY25#`e38FCJh09N!4W*?$O=V!ln_&W>}HJ+4HQB0q+|Cly?vizgc&jE zqPXC%!P)Ta{d%UL>izY#00&~a)#wV6`kCXF^WV%GX=wb<;x4#Yuz`6H(1+_Kd?3Ixvr5R zl)Kj`rh}Jvm5aJ8Y>|z7YgSj&ISO9hSK|ina$mtV$dS1Z*;kne`!@}1xpmuMwQG~$ z4=B_bs=3YrMJCe(JFr^sCfL}CHV}>WmcG*1 z_1riEBua`QK|MGB|C!7D^)~NNKKjJ!Hubh8?d9Gpfa-2Kj51*#>`}`V1MfxKpi0BN z@^XhMiO9KCE`+emF}U#K3s0#e>~GEi1Ha=gJ5&~1W}yPJH_)nk9tH2JQsPy;&A~Kq zTb!Dh-!VIU*6L@l+^>NDr?@kZhq7JcIMe8iEKNvxl^C=jWs9+;G1f?y!6>6db|Ms6 zOIe~C8B$1LEMuK)MWwWirNuI2WKu~Xk!;yI*YnnU{yFFWGk-rbpP75^`+2VA_xoPm z#!FgWI^UL;F%$QHm5-V{u)3qAC)T)w3S_+I&o`qlA-DnxuM-YIBjMebA zYrn1`fDEguXbS_Koe2;c4_3JvRr~gdfY<&R?1GMB+ihR_>()a1%DCFIV>dYWLnu&Y z=zuW=Nc+Ux1}K{sK+#q-RU7c`5|kGVRL?_0$LO+@9uk2ok(p@dUjTey*NKnMgk~1N zsE+i`kb?R~y>Rt!Z|~-{PIMLsfDi*H2+BtQDYD(J2n(@YF(soHWN|5g{P_qC7xT0N z=RY2+$>A50A$|a*SqI3K!jJ9^e>XiTf8PlZ{etj?E9m6y)MOEU$IKWg>3%4dEV{9% z*zHLYL!z>)pU&xAmU&E5b#@K@?*Pl)cE+x+EvBl5wyFH5|6bM4<|)c~-bV?q-0P!8 z0(|f59pL};8NZ4acgcm#`+W9r)BLynucJIe)F%${mL;V;y8AIYccR-E%F4FMUn;Td zCD#*Qzoq|E+HN#b&9gkXzI|gg1j9ESGHqI}^{_Zww$R!y2^%tGi~3HPrYT9$eT5Sy z?>+ye+q{7%R07dfmQz&$0K`zefaFsU7_q~kv1KjsB#vLS#H$wM zg$9ULFxp!8^Nfqfw+=#Fs?90R>sc-(4B}fPtK99VTPZYX{9Nu_`lU+1yfp{ zi7VP$w9py<`co1D9l;9p&xbrgj{@%C0RGd5aYjQ<;+s>%mlYMl){HsgeRi#`Tap5Z zl<^3MZ*uCXVw%O<^*=8jf2t{|t(a($r7IPsE0G`ywO4>Kd%n$6x|dvz94(b&um4io ztAl~mkt9Nfa9xDm_9YH;x4k>^vwFZB zCof8_{bu6$aL_~0Q(ZDIqweXzjkRo_&UC^j{ie=Bok)q&I=iZQfzFIHL&rQpZ@Z1zyl`iWihP3&$iE#J;0h zAh9d?VKhm^87U*oWZ3XW9>?)t(+tSbwqiz3oovxcA|@Sy{E&3N2TGAN-biRDhmLa! z@~wnhw9~T$>`H|j^!hx0c%&>EAdIDnGV<7*mU-pM4aLN@vq+}Cwy}(Up=yJq2sql)# z>Kc>dgOiiWyt0-aGybp0lKiJLkdrnwve$ZXS=!Ezf?nmJ!QZ2kIl6G5y675U%`MhC zrSvU^%Ua!<>&DYM=k_fT11rBgF_5Q{g9@Id?Q}lc=9^@YWcpI_j+v#}`bTL@;(vI0 zK??aJWoSEkO0BYr_&;>K-qm|D&xQODKGL5Z_@;3_A@vdTjY>ue8hWz~dKIp!_#WNA z6g5ltc4>dpLAwHt=hXn*eA3t)`Mv*^;(N-R*C*XaayC&NFXp|4+)}>e{mW{d;sHUL zj32k+c9-=WohYSs!oX61=IeYq-olv%?k#7Up=vao9^2jo;>&9)t0o>SDkH=W`qS3A zAk$}7%!|02I4UkXC}$Jkv~7GO5oHSq0E(u3O+a?UzKdfZl3w7D=TcJJ^CMhfk~vIX zhrV@wrHgD=KtVR}Z4bJ7j$O83)I?4IHTqV>F85Za7LbG&7uTnHh0H+y1so_Oc>81Z zeh*!)Am1x7r!a6%q|>2AJ|{^Am7 zWt1~nJV?eV+8Yw&gp+UUJ>?`TA1*J#C+*Tv`bDSaRx1D~(mF5H7Cd|3{VJnsv4ePK ztEy6B#PlmQK_4}jvU6#cLB1wQ>WS=b&g769K%+xaH`6{&QyGwU>u zjfdwD)A%4gtF`(iVDtKJ?2y>kvI(&cgFVy;Djw`K65h=@FX017sIyZ|TWpTM%5kR2 zkefjUTB4DJJBeck0i8w=mewuROK?BVNZK!xb>;Bp0&B`eQ=DI~xg=`Us_zefEnC&J zu)zwdfTx%sQQ>bFeH^G2TB`P;xH5x*iD~|C=nT5~O=8*Fh?TGMJ?#VWj)BKqJHGRt z-p0`}pX9!{CYEj7-2{cb$_S3~;w=Ox|!PkG%6};BBQG!|Uq_eoeZfo$5G8Kif(f0S2iD{uNbiC?-NvOw* zn|mK}=8e&vwJX+A7geHHB5KMH(j!|hxut%;8j|?Z4JUtfN1uM5Tp>&%ajZXai_>i! zcQD_MnVz~2jD-V7{W6~e1@|X~UTuECmi~bIFxsWYLG=4s@hiCQXVWJ1jYk z^Sg&rxN!o7{zYC{Of$>RR1LOpVG!$E=`qyGK(R++!XENAJ$gC%L3|le z_hVg2KU|yIw|Xm-e680m=^||6go>-U8lN-GsouvCr4rN2=Blo97c6hC_pW14lWlYR z>pA8MvJL*8V?Vtk3v@S}{MtIZQL=L5p^TN=duGjU$n$Z8%9BzxrgS!F@Nm;jy>c=A zzzfPpTjhw7K~XL52(g62?a%c(J^)-oWN$NqW*%S@!9%%y( z?nxyq-_h=3*)-GsZ>2CZzV7-3r7>mq=e+=|IW@sGf>_EfI$xjcv%_cWr|`Z&d&p9< zDbC=sE>Ha!0(($yatjhP4;E`slQZuk%9i!JYJ2L?ja#YQFT)caD>eX|tlCswsy1yb zIaAUM7*B`(Wpgs`MIr6%#tN8cfYRY zDwCvY!YNi+5dwx!v6)ZzFxSec+Bo>3(3oj{3^mf9T`q!SSawI@_~KZm15F%)o3#HC zFBw&=gBM&Ayaq$fKJipp6n9amJCp#|9OTx2Ah>1uxw-!zKIgdX?irJ980sCo_B(&O zgkWJzwE%`XZeMJ_hFbir<83mw&%#}X7ll?{W3k-9Psnc$6~p4PSE0sH1h)oK360=Z z5~!{zOWb2iHjUxomFbkIFK+6V3A#_Yx%g}8^9}#j7Z^0G%f8AE_wy{z_tzE(Zpn-i zGzKUfS6N{%7VR6dwTax4fH|2HYh%l?VV8{uelVN*E9$y7xKJo7hpOLA#1HsuDv1lk znW1a@$0wJTbanOgBKteOkM;J*^`-8?V5Lvk#@Gfku z1$F}P?JY7vXv*XL=UH)v9U{D_9q2fg*s<4WUX+?R z7AGL&lAxsCepKsz@ynWw#vV@909M){*RsiETQ#0+6vGp{J$6extH`)p-e52Q7CBMc z02Ujz6PC4Ins_`bDF<^}WJD0&1lPukzwzDkdBw%WWlQ+3>)R$PVz46?SW|^TGq=u1 zo)`aqpE_oKU|_Y}ekpr{gormCUXAx+u;j?cvnI&L(qLD%cGYOYpDBIC&LF`;d!yev z=_>~Y=Z$r4x@gan&OOf%jfyhNspu)Xvl3bxu@EU7Z+P#a=3lto#)F%1&&2|F@}g8w z+-!|!BoYek&5zMsen0$C4$~JM6|M3i9!qd5o4|*v2^M1c&;I@$(vw9fLOwQZ) + +## Layers + +Template classes for layers containing blocks, and the child class for layers containing ``VoxelBlock`` s. + +* [BlockLayer](@ref nvblox::BlockLayer) +* [VoxelBlockLayer](@ref nvblox::VoxelBlockLayer) + +Typedefs for layers containing specific block types and voxel block types. + +* [TsdfLayer](@ref nvblox::TsdfLayer) +* [EsdfLayer](@ref nvblox::EsdfLayer) +* [ColorLayer](@ref nvblox::ColorLayer) +* [MeshLayer](@ref nvblox::MeshLayer) + +## Layer Cake + +The ``LayerCake`` combines several layers into a single object. + +* [LayerCake](@ref nvblox::LayerCake) + + + + diff --git a/docs/pages/nvblox_node.rst b/docs/pages/nvblox_node.rst deleted file mode 100644 index 7bb2e792..00000000 --- a/docs/pages/nvblox_node.rst +++ /dev/null @@ -1,158 +0,0 @@ - -.. # Package Reference -.. In this section we give an overview of parameters, inputs, and outputs within this repository and their purpose and settings. - -.. ## nvblox_ros -.. The package centers around the `nvblox_node`, whose parameters, inputs, and outputs are described in detail here. - - -.. ### Published Topics - -.. **mesh** ``nvblox_msgs::msg::Mesh`` \ -.. A visualization topic showing the mesh produced from the TSDF in a form that can be seen in RViz using `nvblox_rviz_plugin`. Set ``max_mesh_update_hz`` to control its update rate. - -.. **pointcloud** ``sensor_msgs::msg::PointCloud2`` \ -.. A pointcloud of the 2D ESDF (Euclidean Signed Distance Field), with intensity as the metric distance to the nearest obstacle. Set ``max_esdf_update_hz`` to control its update rate. - -.. **map_slice** ``nvblox_msgs::msg::DistanceMapSlice`` \ -.. A 2D slice of the ESDF, to be consumed by `nvblox_nav2` package for interfacing with Nav2. Set ``max_esdf_update_hz`` to control its update rate. - -.. ### Subscribed Topics - -.. **tf** ``tf2_msgs::msg::TFMessage`` \ -.. The pose of the sensor relative to the global frame is resolved through TF2. Please see the [ROS2 documentation](https://docs.ros.org/en/foxy/Tutorials/Tf2/Introduction-To-Tf2.html) for more details. - -.. **depth/image** ``sensor_msgs::msg::Image`` \ -.. The input depth image to be integrated. Must be paired with a `camera_info` message below. Supports both floating-point (depth in meters) and uint16 (depth in millimeters, OpenNI format). - -.. **depth/camera_info** ``sensor_msgs::msg::CameraInfo`` \ -.. Required topic along with the depth image; contains intrinsic calibration parameters of the depth camera. - -.. **color/image** ``sensor_msgs::msg::Image`` \ -.. Optional input color image to be integrated. Must be paired with a `camera_info` message below. Only used to color the mesh. - -.. **color/camera_info** ``sensor_msgs::msg::CameraInfo`` \ -.. Optional topic along with the color image above, contains intrinsics of the color camera. - -.. ### Services - -.. **save_ply** ``std_srvs::srv::Empty`` \ -.. This service has an empty request and response. Calling this service will write a mesh to disk at the path specified by the `output_dir` parameter. - -.. ### Parameters - -.. A summary of the user settable parameters. All parameters are listed as: - -.. **Parameter** `Default` \ -.. Description. - -.. #### General Parameters - -.. **voxel_size** `0.05` \ -.. Voxel size (in meters) to use for the map. - -.. **esdf** `true` \ -.. Whether to compute the ESDF (map of distances to the nearest obstacle). - -.. **esdf_2d** `true` \ -.. Whether to compute the ESDF in 2D (true) or 3D (false). - -.. **distance_slice** `true` \ -.. Whether to output a distance slice of the ESDF to be used for path planning. - -.. **mesh** `true` \ -.. Whether to output a mesh for visualization in rviz, to be used with `nvblox_rviz_plugin`. - -.. **global_frame** `map` \ -.. The name of the TF frame to be used as the global frame. - -.. **slice_height** `1.0` \ -.. The *output* slice height for the distance slice and ESDF pointcloud. Does not need to be within min and max height below. In units of meters. - -.. **min_height** `0.0` \ -.. The minimum height, in meters, to consider obstacles part of the 2D ESDF slice. - -.. **max_height** `1.0` \ -.. The maximum height, in meters, to consider obstacles part of the 2D ESDF slice. - -.. **max_tsdf_update_hz** `10.0` \ -.. The maximum rate (in Hz) at which to integrate depth images into the TSDF. A value of 0.0 means there is no cap. - -.. **max_color_update_hz** `5.0` \ -.. The maximum rate (in Hz) at which to integrate color images into the color layer. A value of 0.0 means there is no cap. - -.. **max_mesh_update_hz** `5.0` \ -.. The maximum rate (in Hz) at which to update and color the mesh. A value of 0.0 means there is no cap. - -.. **max_esdf_update_hz** `2.0` \ -.. The maximum rate (in Hz) at which to update the ESDF and output the distance slice. A value of 0.0 means there is no cap. - - -.. #### Integrator Settings -.. **tsdf_integrator_max_integration_distance_m** `10.0` \ -.. The maximum distance, in meters, to integrate the TSDF up to. - -.. **tsdf_integrator_truncation_distance_vox** `4.0` \ -.. The truncation distance, in units of voxels, for the TSDF. - -.. **tsdf_integrator_max_weight** `100.0` \ -.. Maximum weight for the TSDF. Setting this number higher will lead to higher-quality reconstructions but worse performance in dynamic scenes. - -.. **mesh_integrator_min_weight** `1e-4` \ -.. Minimum weight of the TSDF to consider for inclusion in the mesh. - -.. **mesh_integrator_weld_vertices** `false` \ -.. Whether to weld identical vertices together in the mesh. Currently reduces the number of vertices by a factor of 5x, but is quite slow so we do not recommend you use this setting. - -.. **color_integrator_max_integration_distance_m** `10.0` \ -.. Maximum distance, in meters, to integrate the color up to. - -.. **esdf_integrator_min_weight** `1e-4` \ -.. Minimum weight of the TSDF to consider for inclusion in the ESDF. - -.. **esdf_integrator_min_site_distance_vox** `1.0` \ -.. Minimum distance to consider a voxel within a surface for the ESDF calculation. - -.. **esdf_integrator_max_distance_m** `10.0` \ -.. Maximum distance to compute the ESDF up to, in meters. - - -.. ## nvblox_nav2 -.. `nvblox_nav2` consists of two parts: an `nvblox_costmap_layer`, which is a Nav2 costmap plugin, and launch files for running the set-up with Nav2 in the loop (described above). - -.. ### `nvblox_costmap_layer` Parameters -.. **nvblox_map_slice_topic** `/nvblox_node/map_slice` \ -.. Topic to listen for the slice (set via parameters to allow easy configuration from a parameter file). - -.. **max_obstacle_distance** `1.0` \ -.. Maximum distance from the surface to consider something to have a collision cost, in meters. This is *NOT* in addition to the inflation distance, but the total. - -.. **inflation_distance** `0.5` \ -.. Distance to inflate all obstacles by, in meters. - -.. # Troubleshooting - -.. ## Reconstruction without the planner (troubleshooting) -.. If something isn't working, or as a quick sanity check, you can run reconstruction without the planner. - -.. Use the `carter_sim.launch.py` launch file parameters `run\_rviz` and `run\_nav2` to turn on and off running rviz and nav2. To run the reconstruction without the planner (but with rviz), run the following: -.. ``` -.. ros2 launch nvblox_nav2 carter_sim.launch.py run_rviz:=true run_nav2:=false -.. ``` - -.. Now, command the robot to spin in place. In another terminal, source your ROS2 workspace again and enter: -.. ``` -.. ros2 topic pub /cmd_vel geometry_msgs/Twist '{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.1}}' -.. ``` -.. You should see the robot spin in a circle and reconstruct its environment. - - -.. ## Do you have a connection to Isaac Sim? -.. A quick way to check if ROS2 is communicating correctly with Isaac Sim is to check whether the depth images are being sent. - -.. ``` -.. ros2 topic hz /left/depth -.. ``` - -.. If this does not receive any messages, then something is wrong with ROS2's connection to Isaac Sim. Either the file hasn't been set up correctly (make sure to run `nvblox_isaac_sim/omniverse_scripts/carter_warehouse.py` rather than opening an OV scene manually), or the scene is paused, or there are different ROS2 Domain IDs at play. - diff --git a/docs/pages/technical.md b/docs/pages/technical.md new file mode 100644 index 00000000..c918f260 --- /dev/null +++ b/docs/pages/technical.md @@ -0,0 +1,26 @@ +# Technical Details + +## Input/Outputs + +Here we discuss the inputs you have to provide to nvblox, and the outputs it produces for downstream tasks. This is the default setup within ROS2 for 2D navigation, but note that other outputs are possible (such as the full 3D distance map). + +_Inputs_: +* **Depth Images**: (@ref nvblox::Image) We require input from a sensor supplying depth per pixel. Examples of such sensors are the Intel Realsense series and Kinect cameras. +* **Camera Intrinsics**: (@ref nvblox::Camera) The intrinsics associated with the camera that generated the depth (or color) image. +* **Sensor Pose**: (@ref nvblox::Transform) We require localization of the depth sensor as input to nvblox +* [Optional] **Color Images**: (@ref nvblox::Image) These can be used to color the reconstruction for visualization. +* [Optional] **LIDAR**: (@ref nvblox::Lidar) Optionally or instead of Depth images, we can also consume LIDAR pointclouds which are reprojected to a cylindrical depth image based on the LIDAR intrinsics specified in this datatype. + +_Outputs_: +* **Distance map slice**: (@ref nvblox::EsdfLayer) A 2D map that expresses the distance at each point from objects reconstructed in the environment. This is typically used by a planner to compute a collision cost map. +* **Mesh**: (@ref nvblox::MeshLayer) We output a mesh for visualization in RVIZ. + +The figure below shows a simple system utilizing nvblox for path planning. + +![System Diagram](images/system_diagram.png) + +## (Brief) Technical Details + +Nvblox builds the reconstructed map in the form of a Truncated Signed Distance Function (TSDF) stored in a 3D voxel grid. This approach is similar to 3D occupancy grid mapping approaches in which occupancy probabilities are stored at each voxel. In contrast however, TSDF-based approaches (like nvblox) store the (signed) distance to the closest surface at each voxel. The surface of the environment can then be extracted as the zero-level set of this voxelized function. Typically TSDF-based reconstructions provide higher quality surface reconstructions. + +In addition to their use in reconstruction, distance fields are also useful for path planning because they provide an immediate means of checking whether potential future robot positions are in collision. This fact, the utility of distance functions for both reconstruction and planning, motivates their use in nvblox (a reconstruction library for path planning). diff --git a/docs/pages/technical.rst b/docs/pages/technical.rst deleted file mode 100644 index ab2be9b6..00000000 --- a/docs/pages/technical.rst +++ /dev/null @@ -1,25 +0,0 @@ -# Input/Outputs - -Here we discuss the inputs you have to provide to nvblox, and the outputs it produces for downstream tasks. - -Inputs: -* **Depth Images**: We require input from a sensor supplying depth per pixel. Examples of such sensors are the Intel Realsense series and Kinect cameras. -* **Sensor Pose**: We require localization of the depth sensor as input to nvblox -* [Optional] **Color Images**: These can be used to color the reconstruction for visualization. - -Outputs: -* **Distance map slice**: A 2D map that expresses the distance at each point from objects reconstructed in the environment. This is typically used by a planner to compute a collision cost map. -* **Mesh**: We output a mesh for visualization in RVIZ. - -The figure below shows a simple system utilizing nvblox for path planning. - -
- - - - -# (Brief) Technical Details - -Nvblox builds the reconstructed map in the form of a Truncated Signed Distance Function (TSDF) stored in a 3D voxel grid. This approach is similar to 3D occupancy grid mapping approaches in which occupancy probabilities are stored at each voxel. In contrast however, TSDF-based approaches (like nvblox) store the (signed) distance to the closest surface at each voxel. The surface of the environment can then be extracted as the zero-level set of this voxelized function. Typically TSDF-based reconstructions provide higher quality surface reconstructions. - -In addition to their use in reconstruction, distance fields are also useful for path planning because they provide an immediate means of checking whether potential future robot positions are in collision. This fact, the utility of distance functions for both reconstruction and planning, motivates their use in nvblox (a reconstruction library for path planning). diff --git a/docs/redistributable.md b/docs/redistributable.md new file mode 100644 index 00000000..cb345766 --- /dev/null +++ b/docs/redistributable.md @@ -0,0 +1,51 @@ +# Redistributable Building +This will walk you through how to build a single libnvblox shared library with only static dependencies. The dependencies must be built manually with -fPIC (position independent code) and linked as static libraries. +You generally shouldn't need to do this except for building nvblox to be included in Bazel for example; the exported targets should work fine for inclusion in CMake projects. + +## Step 1: Install dependencies +**Sqlite3**: +Download here: https://www.sqlite.org/2022/sqlite-autoconf-3390400.tar.gz + +Unzip & build using this command: +``` +CFLAGS=-fPIC ./configure --prefix=/home/USERNAME/code/external/sqlite-autoconf-3390400/install/ +``` + +**glog**: +Download here: https://github.com/google/glog/archive/refs/tags/v0.4.0.zip + +Unzip & build using this command: +``` +mkdir build install +cd build +cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ +-DCMAKE_INSTALL_PREFIX=/home/USERNAME/code/external/glog-0.4.0/install/ \ +-DWITH_GFLAGS=OFF -DBUILD_SHARED_LIBS=OFF \ +&& make -j8 && make install +``` + +**gflags**: +Download here: https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip + +Unzip & build using this command: +``` +mkdir build install +cd build +cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ +-DCMAKE_INSTALL_PREFIX=/home/USERNAME/code/external/gflags-2.2.2/install/ \ +-DGFLAGS_BUILD_STATIC_LIBS=ON -DGFLAGS=google \ +&& make -j8 && make install +``` + +## Step 2: Build nvblox +Build nvblox with the paths set to where you've unzipped and built the dependencies: +``` +cd nvblox/ +mkdir build install +cmake .. -DCMAKE_INSTALL_PREFIX=/home/helen/code/nvblox/nvblox/install/ \ +-DBUILD_FOR_ALL_ARCHS=TRUE -DBUILD_REDISTRIBUTABLE=TRUE \ +-DSQLITE3_BASE_PATH="/home/USERNAME/code/external/sqlite-autoconf-3390400/install/" \ +-DGLOG_BASE_PATH="/home/USERNAME/code/external/glog-0.4.0/install/" \ +-DGFLAGS_BASE_PATH="/home/USERNAME/code/external/gflags-2.2.2/install/" \ +&& make -j8 && make install +``` \ No newline at end of file diff --git a/docs/root.rst b/docs/root.rst new file mode 100644 index 00000000..50cba87b --- /dev/null +++ b/docs/root.rst @@ -0,0 +1,8 @@ +======= +Table of Contents +======= + +.. toctree:: + :maxdepth: 1 + :glob: + root diff --git a/docs/pages/examples/core_example.rst b/docs/rst/examples/core_example.rst similarity index 100% rename from docs/pages/examples/core_example.rst rename to docs/rst/examples/core_example.rst diff --git a/docs/pages/examples/index.rst b/docs/rst/examples/index.rst similarity index 100% rename from docs/pages/examples/index.rst rename to docs/rst/examples/index.rst diff --git a/docs/pages/examples/ros_example.rst b/docs/rst/examples/ros_example.rst similarity index 100% rename from docs/pages/examples/ros_example.rst rename to docs/rst/examples/ros_example.rst diff --git a/docs/index.rst b/docs/rst/index.rst similarity index 74% rename from docs/index.rst rename to docs/rst/index.rst index 7e1f72d6..384ed59d 100644 --- a/docs/index.rst +++ b/docs/rst/index.rst @@ -1,5 +1,5 @@ ======= -nvblox +Introduction to nvblox ======= Nvblox is a package for building a 3D reconstruction of the environment around your robot from sensor observations in real-time. The reconstruction is intended to be used by path planners to generate collision-free paths. Under the hood, nvblox uses NVIDIA CUDA to accelerate this task to allow operation at real-time rates. This repository contains ROS2 integration for the nvblox core library. @@ -12,27 +12,14 @@ Nvblox is a package for building a 3D reconstruction of the environment around y .. |pic2| image:: /images/nvblox_navigation_trim.gif :width: 45% -**Left**: nvblox used for reconstruction on a scan from the `Sun3D Dataset `_. **Right**: the nvblox ROS2 wrapper used to construct a costmap for `ROS2 Nav2 `_ for navigating of a robot inside `Isaac Sim `_. +**Left**: nvblox used for reconstruction on a scan from the `Sun3D Dataset `_. +**Right**: the nvblox ROS2 wrapper used to construct a costmap for `ROS2 Nav2 `_ for navigating of a robot inside `Isaac Sim `_. Nvblox is composed of two packages * `nvblox Core Library `_ Contains the core C++/CUDA reconstruction library. * `nvblox ROS2 Interface `_ Contains a ROS2 wrapper and integrations for simulation and path planning. Internally builds the core library. -.. toctree:: - :maxdepth: 1 - :caption: Getting Started - - pages/installation/index - pages/examples/index - - .. :glob: - - .. pages/* - - .. api/library_root - - diff --git a/docs/pages/installation/core.rst b/docs/rst/installation/core.rst similarity index 100% rename from docs/pages/installation/core.rst rename to docs/rst/installation/core.rst diff --git a/docs/pages/installation/index.rst b/docs/rst/installation/index.rst similarity index 100% rename from docs/pages/installation/index.rst rename to docs/rst/installation/index.rst diff --git a/docs/pages/installation/ros.rst b/docs/rst/installation/ros.rst similarity index 100% rename from docs/pages/installation/ros.rst rename to docs/rst/installation/ros.rst diff --git a/docs/pages/integrators.rst b/docs/rst/integrators.rst similarity index 100% rename from docs/pages/integrators.rst rename to docs/rst/integrators.rst diff --git a/docs/pages/map.rst b/docs/rst/map.rst similarity index 98% rename from docs/pages/map.rst rename to docs/rst/map.rst index 5220da2b..bcc12d90 100644 --- a/docs/pages/map.rst +++ b/docs/rst/map.rst @@ -37,7 +37,7 @@ Storage of the mesh in this way allows us to perform incremental updates (we onl Layers ====== -Template classes for layers containing blocks, and the child class for layers containing ``VoxelBlock``s. +Template classes for layers containing blocks, and the child class for layers containing ``VoxelBlock`` s. * :ref:`BlockLayer