diff --git a/.gitignore b/.gitignore index e4a13795..b9286b30 100644 --- a/.gitignore +++ b/.gitignore @@ -113,6 +113,7 @@ target/ # Jupyter Notebook .ipynb_checkpoints +.jupyter/ # IPython profile_default/ diff --git a/main.py b/main.py index f316c80f..8169df6b 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,7 @@ from utama_core.strategy.examples import ( DefenceStrategy, GoToBallExampleStrategy, + PointCycleStrategy, RobotPlacementStrategy, StartupStrategy, TwoRobotPlacementStrategy, @@ -17,7 +18,7 @@ def main(): custom_bounds = FieldBounds(top_left=(2.25, 1.5), bottom_right=(4.5, -1.5)) runner = StrategyRunner( - strategy=TwoRobotPlacementStrategy(first_robot_id=0, second_robot_id=1, field_bounds=custom_bounds), + strategy=PointCycleStrategy(n_robots=2, field_bounds=custom_bounds, endpoint_tolerance=0.1, seed=42), my_team_is_yellow=True, my_team_is_right=True, mode="rsim", @@ -25,7 +26,7 @@ def main(): exp_enemy=0, replay_writer_config=ReplayWriterConfig(replay_name="test_replay", overwrite_existing=True), print_real_fps=True, - profiler_name=None + profiler_name=None, ) runner.my_strategy.render() runner.run() diff --git a/pixi.lock b/pixi.lock index d75f512f..038b03df 100644 --- a/pixi.lock +++ b/pixi.lock @@ -9,9 +9,9 @@ environments: linux-64: - conda: https://prefix.dev/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - - conda: https://prefix.dev/conda-forge/noarch/adwaita-icon-theme-48.1-unix_1.conda + - conda: https://prefix.dev/conda-forge/noarch/adwaita-icon-theme-49.0-unix_0.conda - conda: https://prefix.dev/conda-forge/linux-64/alsa-lib-1.2.14-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/noarch/anyio-4.10.0-pyhe01879c_0.conda + - conda: https://prefix.dev/conda-forge/noarch/anyio-4.11.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda - conda: https://prefix.dev/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 @@ -19,24 +19,24 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/attr-2.5.2-h39aace5_0.conda - conda: https://prefix.dev/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://prefix.dev/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.11.12-hbd8a1cb_0.conda - conda: https://prefix.dev/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda - - conda: https://prefix.dev/conda-forge/noarch/certifi-2025.8.3-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/cffi-1.17.1-py311h5b438cf_1.conda + - conda: https://prefix.dev/conda-forge/noarch/certifi-2025.11.12-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda - conda: https://prefix.dev/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/noarch/click-8.2.1-pyh707e725_0.conda - - conda: https://prefix.dev/conda-forge/noarch/cloudpickle-3.1.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/click-8.3.1-pyh707e725_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cloudpickle-3.1.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/cryptography-45.0.7-py311h8488d03_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/cryptography-46.0.3-py311h8488d03_0.conda - conda: https://prefix.dev/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda - conda: https://prefix.dev/conda-forge/linux-64/dbus-1.16.2-h3c4dab8_0.conda - conda: https://prefix.dev/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/editables-0.5-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/epoxy-1.5.10-h166bdaf_1.tar.bz2 + - conda: https://prefix.dev/conda-forge/linux-64/epoxy-1.5.10-hb03c661_2.conda - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/farama-notifications-0.0.4-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/noarch/filelock-3.19.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/filelock-3.20.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/fluidsynth-2.3.7-hd992666_0.conda - conda: https://prefix.dev/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 - conda: https://prefix.dev/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 @@ -44,21 +44,21 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda - conda: https://prefix.dev/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda - conda: https://prefix.dev/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - - conda: https://prefix.dev/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 - - conda: https://prefix.dev/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda + - conda: https://prefix.dev/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/freetype-2.14.1-ha770c72_0.conda - conda: https://prefix.dev/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/gdk-pixbuf-2.44.1-h2b0a6b4_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/gdk-pixbuf-2.44.4-h2b0a6b4_0.conda - conda: https://prefix.dev/conda-forge/linux-64/gettext-0.25.1-h3f43e3d_1.conda - conda: https://prefix.dev/conda-forge/linux-64/gettext-tools-0.25.1-h3f43e3d_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/glib-tools-2.86.0-hf516916_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/glib-tools-2.86.1-hf516916_2.conda - conda: https://prefix.dev/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda - conda: https://prefix.dev/conda-forge/linux-64/graphviz-13.1.2-h87b6fe6_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/gtk3-3.24.43-h0c6a113_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/gtk3-3.24.43-h993cebd_6.conda - conda: https://prefix.dev/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda - conda: https://prefix.dev/conda-forge/linux-64/gymnasium-1.0.0-np2py311hec5889a_2.conda - conda: https://prefix.dev/conda-forge/noarch/h11-0.16.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/harfbuzz-11.4.5-h15599e2_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/harfbuzz-12.2.0-h15599e2_0.conda - conda: https://prefix.dev/conda-forge/noarch/hatch-1.14.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/hatchling-1.27.0-pypyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_2.tar.bz2 @@ -68,85 +68,87 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/hyperlink-21.0.0-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/linux-64/icu-75.1-he02047a_0.conda - - conda: https://prefix.dev/conda-forge/noarch/identify-2.6.14-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/identify-2.6.15-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda - conda: https://prefix.dev/conda-forge/noarch/importlib_resources-6.5.2-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/jack-1.9.22-hf4617a5_3.conda - conda: https://prefix.dev/conda-forge/noarch/jaraco.classes-3.4.0-pyhd8ed1ab_2.conda - conda: https://prefix.dev/conda-forge/noarch/jaraco.context-6.0.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jaraco.functools-4.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jax-jumpy-1.0.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/jeepney-0.9.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/noarch/keyring-25.6.0-pyha804496_0.conda + - conda: https://prefix.dev/conda-forge/noarch/keyring-25.7.0-pyha804496_0.conda - conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - conda: https://prefix.dev/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.45-h1aa0949_0.conda - conda: https://prefix.dev/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libasprintf-0.25.1-h3f43e3d_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libasprintf-devel-0.25.1-h3f43e3d_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libavif16-1.3.0-h6395336_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libblas-3.9.0-35_h59b9bed_openblas.conda - - conda: https://prefix.dev/conda-forge/linux-64/libcap-2.75-h39aace5_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libcblas-3.9.0-35_he106b2a_openblas.conda + - conda: https://prefix.dev/conda-forge/linux-64/libblas-3.11.0-1_h4a7cf45_openblas.conda + - conda: https://prefix.dev/conda-forge/linux-64/libcap-2.77-h3ff7636_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libcblas-3.11.0-1_h0358290_openblas.conda - conda: https://prefix.dev/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libdeflate-1.24-h86f0d12_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libegl-1.7.0-ha4b6fd6_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.3-hecca717_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libffi-3.5.2-h9ec8514_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libfreetype-2.13.3-ha770c72_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libfreetype6-2.13.3-h48d6fc4_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcrypt-lib-1.11.1-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libfreetype-2.14.1-ha770c72_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libfreetype6-2.14.1-h73754d4_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-h767d61c_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_7.conda - conda: https://prefix.dev/conda-forge/linux-64/libgd-2.3.3-h6f5c62b_11.conda - conda: https://prefix.dev/conda-forge/linux-64/libgettextpo-0.25.1-h3f43e3d_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libgettextpo-devel-0.25.1-h3f43e3d_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgfortran-15.1.0-h69a702a_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-15.2.0-hcd61629_7.conda - conda: https://prefix.dev/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libglib-2.86.0-h1fed272_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libglib-2.86.1-h32235b2_2.conda - conda: https://prefix.dev/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda - conda: https://prefix.dev/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgpg-error-1.55-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-h767d61c_7.conda - conda: https://prefix.dev/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/liblapack-3.9.0-35_h7ac8fdf_openblas.conda + - conda: https://prefix.dev/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/liblapack-3.11.0-1_h47877c9_openblas.conda - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/libmad-0.15.1b-h0b41bf4_1001.conda - conda: https://prefix.dev/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libogg-1.3.5-hd0c01bc_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda - conda: https://prefix.dev/conda-forge/linux-64/libopus-1.5.2-hd0c01bc_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libpciaccess-0.18-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libpng-1.6.50-h421ea60_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libprotobuf-3.20.2-h6239696_0.tar.bz2 - - conda: https://prefix.dev/conda-forge/linux-64/librsvg-2.58.4-he92a37e_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/librsvg-2.60.0-h61e6d4b_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libsystemd0-257.7-h4e0b6ca_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libtiff-4.7.0-h8261f1e_6.conda - - conda: https://prefix.dev/conda-forge/linux-64/libudev1-257.7-hbe16f8c_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.51.0-hee844dc_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h8f9b012_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.2.0-h4852527_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsystemd0-257.10-hd0affe5_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libudev1-257.10-hd0affe5_2.conda - conda: https://prefix.dev/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda - conda: https://prefix.dev/conda-forge/linux-64/liburing-2.12-hb700be7_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libusb-1.0.29-h73b1eb8_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.41.1-he9a06e4_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.41.2-he9a06e4_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libvorbis-1.3.7-h54a6638_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/libvulkan-loader-1.4.328.1-h5279c79_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxkbcommon-1.13.0-hca5e8e5_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxml2-16-2.15.1-ha9997c6_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.15.1-h26afc86_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - conda: https://prefix.dev/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda @@ -154,7 +156,7 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - conda: https://prefix.dev/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/numpy-2.0.2-py311h71ddf71_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.5.2-h26f9b46_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.6.0-h26f9b46_0.conda - conda: https://prefix.dev/conda-forge/linux-64/opusfile-0.12-h3358134_2.conda - conda: https://prefix.dev/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pango-1.56.4-hadf4263_0.conda @@ -162,78 +164,79 @@ environments: - conda: https://prefix.dev/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda - conda: https://prefix.dev/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda - - conda: https://prefix.dev/conda-forge/noarch/platformdirs-4.4.0-pyhcf101f3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/linux-64/portaudio-19.6.0-h7c63dc7_9.conda - - conda: https://prefix.dev/conda-forge/linux-64/portmidi-2.0.6-hf4617a5_0.conda - - conda: https://prefix.dev/conda-forge/noarch/pre-commit-4.3.0-pyha770c72_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/portmidi-2.0.7-h3cb78e3_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pre-commit-4.4.0-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/linux-64/protobuf-3.20.2-py311ha362b79_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda - conda: https://prefix.dev/conda-forge/noarch/ptyprocess-0.7.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/pulseaudio-client-17.0-hac146a9_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/pulseaudio-client-17.0-h9a6aba3_3.conda - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/linux-64/pygame-2.6.1-py311h3209946_0.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pyserial-3.5-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.11.13-h9e4cc4f_0_cpython.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.11.14-hd63d673_2_cpython.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.11-8_cp311.conda - - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py311h2dc5d0c_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_0.conda - conda: https://prefix.dev/conda-forge/linux-64/rav1e-0.7.1-h8fae777_3.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda - conda: https://prefix.dev/conda-forge/noarch/rich-14.2.0-pyhcf101f3_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/ruff-0.12.12-h718f522_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/sdl2-2.32.54-h3f2d84a_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/ruff-0.14.5-h813ae00_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/sdl2-2.32.56-h54a6638_0.conda - conda: https://prefix.dev/conda-forge/linux-64/sdl2_image-2.8.2-h06ee604_1.conda - conda: https://prefix.dev/conda-forge/linux-64/sdl2_mixer-2.6.3-h8830914_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/sdl2_ttf-2.24.0-hc1d668e_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/sdl3-3.2.22-h68140b3_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/secretstorage-3.3.3-py311h38be061_4.conda + - conda: https://prefix.dev/conda-forge/linux-64/sdl2_ttf-2.24.0-h287479f_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/sdl3-3.2.26-h68140b3_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/secretstorage-3.4.1-py311h38be061_0.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda - - conda: https://prefix.dev/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda - conda: https://prefix.dev/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://prefix.dev/conda-forge/noarch/snakeviz-2.2.2-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://prefix.dev/conda-forge/linux-64/svt-av1-3.1.2-hecca717_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda - - conda: https://prefix.dev/conda-forge/noarch/tomli-2.2.1-pyhe01879c_2.conda + - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_ha0e22de_103.conda + - conda: https://prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/tornado-6.5.2-py311h49ec1c0_1.conda - - conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.8.26.11-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/tornado-6.5.2-py311h49ec1c0_2.conda + - conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.11.14.15-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/ukkonen-1.0.1-py311hd18a35c_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/ukkonen-1.0.1-py311hdf67eae_6.conda - conda: https://prefix.dev/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/uv-0.8.15-h2f8d451_0.conda - - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.34.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/uv-0.9.10-h76e24b7_0.conda + - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.35.4-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/wayland-1.24.0-hd6090a7_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/xkeyboard-config-2.46-hb03c661_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxinerama-1.1.5-h5888daf_1.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxscrnsaver-1.2.4-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda - conda: https://prefix.dev/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/zstandard-0.24.0-py311h4854a17_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/zstandard-0.25.0-py311haee01d2_1.conda - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda - pypi: https://files.pythonhosted.org/packages/fb/06/6a7c30c3519181263e1bbf0cbea67ef4a43a64443ee16717c7d760214943/lenses-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/39/1c/9f32299572bce7c1d46ca98425d82f3fe6723a526f05a01b39d491cbfdf6/py_trees-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7d/0a/2e0c30342586dabb0b4b7946393a7aeb725fca7b4549fb02e128a1a0fe87/py_trees-2.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/32/a7125fb28c4261a627f999d5fb4afff25b523800faed2c30979949d6facd/pydot-4.0.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl osx-arm64: - conda: https://prefix.dev/conda-forge/noarch/adwaita-icon-theme-49.0-unix_0.conda - conda: https://prefix.dev/conda-forge/noarch/anyio-4.11.0-pyhcf101f3_0.conda @@ -242,13 +245,13 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/backports-1.0-pyhd8ed1ab_5.conda - conda: https://prefix.dev/conda-forge/noarch/backports.tarfile-1.2.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda - - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.11.12-hbd8a1cb_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/cairo-1.18.4-h6a3b0d2_0.conda - - conda: https://prefix.dev/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/cffi-2.0.0-py311hcfc1310_0.conda + - conda: https://prefix.dev/conda-forge/noarch/certifi-2025.11.12-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/cffi-2.0.0-py311hd10dc20_1.conda - conda: https://prefix.dev/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - - conda: https://prefix.dev/conda-forge/noarch/cloudpickle-3.1.1-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/noarch/click-8.3.1-pyh707e725_0.conda + - conda: https://prefix.dev/conda-forge/noarch/cloudpickle-3.1.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/dav1d-1.2.1-hb547adb_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/dbus-1.16.2-hda038a8_0.conda @@ -265,21 +268,21 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/fontconfig-2.15.0-h1383a14_1.conda - conda: https://prefix.dev/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - - conda: https://prefix.dev/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 + - conda: https://prefix.dev/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/freetype-2.14.1-hce30654_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/fribidi-1.0.16-hc919400_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/gdk-pixbuf-2.44.4-h7542897_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/gettext-0.25.1-h3dcc1bd_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/gettext-tools-0.25.1-h493aca8_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/glib-tools-2.86.0-hb9d6e3a_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/glib-tools-2.86.1-hb9d6e3a_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/graphite2-1.3.14-hec049ff_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/graphviz-13.1.2-hcd33d8b_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/gtk3-3.24.43-h07173f4_5.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/gtk3-3.24.43-h5febe37_6.conda - conda: https://prefix.dev/conda-forge/osx-arm64/gts-0.7.6-he42f4ea_4.conda - conda: https://prefix.dev/conda-forge/osx-arm64/gymnasium-1.0.0-np2py311he8d3834_2.conda - conda: https://prefix.dev/conda-forge/noarch/h11-0.16.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/harfbuzz-11.5.1-haf38c7b_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/harfbuzz-12.2.0-haf38c7b_0.conda - conda: https://prefix.dev/conda-forge/noarch/hatch-1.14.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/hatchling-1.27.0-pypyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/hicolor-icon-theme-0.17-hce30654_2.tar.bz2 @@ -298,18 +301,18 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/jaraco.context-6.0.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jaraco.functools-4.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/jax-jumpy-1.0.0-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/noarch/keyring-25.6.0-pyh534df25_0.conda + - conda: https://prefix.dev/conda-forge/noarch/keyring-25.7.0-pyh534df25_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/lame-3.100-h1a8c8d9_1003.tar.bz2 - conda: https://prefix.dev/conda-forge/osx-arm64/lerc-4.0.0-hd64df32_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libasprintf-0.25.1-h493aca8_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libasprintf-devel-0.25.1-h493aca8_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libavif16-1.3.0-hb06b76e_2.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libblas-3.9.0-37_h51639a9_openblas.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libcblas-3.9.0-37_hb0561ab_openblas.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.4-hf598326_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libdeflate-1.24-h5773f1b_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libblas-3.11.0-1_h51639a9_openblas.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcblas-3.11.0-1_hb0561ab_openblas.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.6-hf598326_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libdeflate-1.25-hc11a715_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.3-haf25636_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.5.2-he5f378a_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libflac-1.4.3-hb765f3a_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libfreetype-2.14.1-hce30654_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libfreetype6-2.14.1-h6da58f4_0.conda @@ -318,30 +321,30 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/libgettextpo-devel-0.25.1-h493aca8_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libgfortran-15.2.0-hfcf01ff_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libgfortran5-15.2.0-h742603c_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.86.1-he69a767_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libiconv-1.18-h23cfdf5_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libintl-0.25.1-h493aca8_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libintl-devel-0.25.1-h493aca8_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libjpeg-turbo-3.1.0-h5505292_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/liblapack-3.9.0-37_hd9741b5_openblas.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libjpeg-turbo-3.1.2-hc919400_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/liblapack-3.11.0-1_hd9741b5_openblas.conda - conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libmad-0.15.1b-h1a8c8d9_1001.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libogg-1.3.5-h48c0fde_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_ha158390_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_ha158390_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libopus-1.5.2-h48c0fde_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libpng-1.6.50-h280e0eb_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libprotobuf-3.20.2-hb5ab8b9_0.tar.bz2 - conda: https://prefix.dev/conda-forge/osx-arm64/librsvg-2.60.0-h5c55ec3_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libsndfile-1.2.2-h9739721_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libtiff-4.7.1-h7dc4979_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libsqlite-3.51.0-h8adb53f_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libtiff-4.7.1-h4030677_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libusb-1.0.29-hbc156a2_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libvorbis-1.3.7-h81086ad_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libvulkan-loader-1.4.328.1-h49c215f_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libwebp-base-1.6.0-h07db88b_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-16-2.15.1-h0ff4647_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-openmp-21.1.4-h4a912ad_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/llvm-openmp-21.1.6-h4a912ad_0.conda - conda: https://prefix.dev/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/more-itertools-10.8.0-pyhd8ed1ab_0.conda @@ -349,7 +352,7 @@ environments: - conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - conda: https://prefix.dev/conda-forge/noarch/nodeenv-1.9.1-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/numpy-2.0.2-py311h649a571_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.5.4-h5503f6c_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.6.0-h5503f6c_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/opusfile-0.12-h5643135_2.conda - conda: https://prefix.dev/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pango-1.56.4-h875632e_0.conda @@ -360,8 +363,8 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/portaudio-19.6.0-h13dd4ca_9.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/portmidi-2.0.6-h286801f_0.conda - - conda: https://prefix.dev/conda-forge/noarch/pre-commit-4.3.0-pyha770c72_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/portmidi-2.0.7-haf25636_0.conda + - conda: https://prefix.dev/conda-forge/noarch/pre-commit-4.4.0-pyha770c72_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/protobuf-3.20.2-py311ha397e9f_1.conda - conda: https://prefix.dev/conda-forge/noarch/ptyprocess-0.7.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda @@ -369,45 +372,44 @@ environments: - conda: https://prefix.dev/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pyserial-3.5-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-8.3.4-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.11.14-hec0b533_1_cpython.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.11.14-h18782d2_2_cpython.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.11-8_cp311.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.3-py311ha9b3269_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/rav1e-0.7.1-h0716509_3.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda - conda: https://prefix.dev/conda-forge/noarch/rich-14.2.0-pyhcf101f3_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/ruff-0.14.1-h492a034_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ruff-0.14.5-h382de68_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2-2.32.56-h248ca61_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2_image-2.8.2-h376e2e1_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2_mixer-2.6.3-h4fe3bdc_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2_ttf-2.24.0-h49b19f9_1.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/sdl3-3.2.24-h919df07_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2_ttf-2.24.0-h443c5de_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/sdl3-3.2.26-h919df07_0.conda - conda: https://prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda - - conda: https://prefix.dev/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda - conda: https://prefix.dev/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - conda: https://prefix.dev/conda-forge/noarch/snakeviz-2.2.2-pyhd8ed1ab_1.conda - - conda: https://prefix.dev/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_1.conda + - conda: https://prefix.dev/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/svt-av1-3.1.2-h12ba402_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_3.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-w-1.2.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/tomlkit-0.13.3-pyha770c72_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/tornado-6.5.2-py311h3696347_1.conda - - conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.9.11.17-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/tornado-6.5.2-py311h9408147_2.conda + - conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.11.14.15-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/ukkonen-1.0.1-py311h2c37856_5.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/ukkonen-1.0.1-py311h57a9ea7_6.conda - conda: https://prefix.dev/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/uv-0.9.5-h194b5f9_0.conda - - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.35.3-pyhd8ed1ab_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/uv-0.9.10-h1bde295_0.conda + - conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.35.4-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/yaml-0.2.5-h925e9cb_3.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-3.23.0-pyhd8ed1ab_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/zstandard-0.25.0-py311h5bb9006_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/zstandard-0.25.0-py311h5bb9006_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/zstd-1.5.7-h6491c7d_2.conda - pypi: https://files.pythonhosted.org/packages/fb/06/6a7c30c3519181263e1bbf0cbea67ef4a43a64443ee16717c7d760214943/lenses-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/39/1c/9f32299572bce7c1d46ca98425d82f3fe6723a526f05a01b39d491cbfdf6/py_trees-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7d/0a/2e0c30342586dabb0b4b7946393a7aeb725fca7b4549fb02e128a1a0fe87/py_trees-2.4.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7e/32/a7125fb28c4261a627f999d5fb4afff25b523800faed2c30979949d6facd/pydot-4.0.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl robosim: channels: - url: https://prefix.dev/conda-forge/ @@ -417,44 +419,45 @@ environments: linux-64: - conda: https://prefix.dev/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - conda: https://prefix.dev/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 - - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda - conda: https://prefix.dev/conda-forge/linux-64/c-ares-1.34.5-hb9d3cd8_0.conda - - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.11.12-hbd8a1cb_0.conda - conda: https://prefix.dev/conda-forge/linux-64/cmake-3.26.4-hcfe8598_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/expat-2.7.1-hecca717_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/expat-2.7.3-hecca717_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/icu-75.1-he02047a_0.conda - conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda + - conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.45-h1aa0949_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libccd-double-2.1-h59595ed_3.conda - - conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.14.1-h332b0f4_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.17.0-h4e3cde8_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libev-4.33-hd590300_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda + - conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.3-hecca717_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libffi-3.5.2-h9ec8514_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-h767d61c_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-h767d61c_7.conda - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/liblzma-devel-5.8.1-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libode-0.16.6-h18afd86_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.51.0-hee844dc_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda - - conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.41.1-he9a06e4_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h8f9b012_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.2.0-h4852527_7.conda + - conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.41.2-he9a06e4_0.conda - conda: https://prefix.dev/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - conda: https://prefix.dev/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda - conda: https://prefix.dev/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda - - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.5.2-h26f9b46_0.conda + - conda: https://prefix.dev/conda-forge/linux-64/openssl-3.6.0-h26f9b46_0.conda - conda: https://prefix.dev/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda - - conda: https://prefix.dev/conda-forge/linux-64/python-3.10.18-hd6af730_0_cpython.conda + - conda: https://prefix.dev/conda-forge/linux-64/python-3.10.19-h3c07f61_2_cpython.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.10-8_cp310.conda - conda: https://prefix.dev/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda - conda: https://prefix.dev/conda-forge/linux-64/rhash-1.4.3-hd590300_2.conda - - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda + - conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_ha0e22de_103.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-5.8.1-hbcc6ac9_2.conda - conda: https://prefix.dev/conda-forge/linux-64/xz-gpl-tools-5.8.1-hbcc6ac9_2.conda @@ -466,34 +469,34 @@ environments: osx-arm64: - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda - conda: https://prefix.dev/conda-forge/osx-arm64/c-ares-1.34.5-h5505292_0.conda - - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda + - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.11.12-hbd8a1cb_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/cmake-3.26.4-hc0af03a_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/expat-2.7.1-hec049ff_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/expat-2.7.3-haf25636_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/icu-75.1-hfee45f7_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/krb5-1.21.3-h237132a_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libccd-double-2.1-h9a09cb3_2.tar.bz2 - - conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.16.0-hdece5d2_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.4-hf598326_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.17.0-hdece5d2_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.6-hf598326_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.3-haf25636_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.5.2-he5f378a_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-5.8.1-h39f12f2_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/liblzma-devel-5.8.1-h39f12f2_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libnghttp2-1.67.0-hc438710_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libode-0.16.6-py310h46abf29_0.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/libsqlite-3.51.0-h8adb53f_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libuv-1.51.0-h6caf38d_1.conda - conda: https://prefix.dev/conda-forge/osx-arm64/libzlib-1.3.1-h8359307_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/ncurses-6.5-h5e97a16_3.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.5.4-h5503f6c_0.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.6.0-h5503f6c_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/pthread-stubs-0.4-hd74edd7_1002.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.10.19-h14e4db3_1_cpython.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/python-3.10.19-hcd7f573_2_cpython.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.10-8_cp310.conda - conda: https://prefix.dev/conda-forge/osx-arm64/readline-8.2-h1d1bf99_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/rhash-1.4.3-hb547adb_2.conda - - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda + - conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_3.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-5.8.1-h9a6d368_2.conda - conda: https://prefix.dev/conda-forge/osx-arm64/xz-gpl-tools-5.8.1-h9a6d368_2.conda @@ -524,18 +527,6 @@ packages: purls: [] size: 23621 timestamp: 1650670423406 -- conda: https://prefix.dev/conda-forge/noarch/adwaita-icon-theme-48.1-unix_1.conda - sha256: f52307d3ff839bf4a001cb14b3944f169e46e37982a97c3d52cbf48a0cfe2327 - md5: 388097ca1f27fc28e0ef1986dd311891 - depends: - - __unix - - hicolor-icon-theme - - librsvg - license: LGPL-3.0-or-later OR CC-BY-SA-3.0 - license_family: LGPL - purls: [] - size: 621553 - timestamp: 1755882037787 - conda: https://prefix.dev/conda-forge/noarch/adwaita-icon-theme-49.0-unix_0.conda sha256: a362b4f5c96a0bf4def96be1a77317e2730af38915eb9bec85e2a92836501ed7 md5: b3f0179590f3c0637b7eb5309898f79e @@ -559,25 +550,6 @@ packages: purls: [] size: 566531 timestamp: 1744668655747 -- conda: https://prefix.dev/conda-forge/noarch/anyio-4.10.0-pyhe01879c_0.conda - sha256: d1b50686672ebe7041e44811eda563e45b94a8354db67eca659040392ac74d63 - md5: cc2613bfa71dec0eb2113ee21ac9ccbf - depends: - - exceptiongroup >=1.0.2 - - idna >=2.8 - - python >=3.9 - - sniffio >=1.1 - - typing_extensions >=4.5 - - python - constrains: - - trio >=0.26.1 - - uvloop >=0.21 - license: MIT - license_family: MIT - purls: - - pkg:pypi/anyio?source=compressed-mapping - size: 134857 - timestamp: 1754315087747 - conda: https://prefix.dev/conda-forge/noarch/anyio-4.11.0-pyhcf101f3_0.conda sha256: 7378b5b9d81662d73a906fabfc2fb81daddffe8dc0680ed9cda7a9562af894b0 md5: 814472b61da9792fae28156cb9ee54f5 @@ -710,17 +682,17 @@ packages: - pkg:pypi/backports-tarfile?source=hash-mapping size: 32786 timestamp: 1733325872620 -- conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-h4bc722e_7.conda - sha256: 5ced96500d945fb286c9c838e54fa759aa04a7129c59800f0846b4335cee770d - md5: 62ee74e96c5ebb0af99386de58cf9553 +- conda: https://prefix.dev/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + sha256: c30daba32ddebbb7ded490f0e371eae90f51e72db620554089103b4a6934b0d5 + md5: 51a19bba1b8ebfb60df25cde030b7ebc depends: - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 + - libgcc >=14 license: bzip2-1.0.6 license_family: BSD purls: [] - size: 252783 - timestamp: 1720974456583 + size: 260341 + timestamp: 1757437258798 - conda: https://prefix.dev/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_8.conda sha256: b456200636bd5fecb2bec63f7e0985ad2097cf1b83d60ce0b6968dffa6d02aa1 md5: 58fd217444c2a5701a44244faf518206 @@ -752,24 +724,15 @@ packages: purls: [] size: 179696 timestamp: 1744128058734 -- conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.10.5-hbd8a1cb_0.conda - sha256: 3b5ad78b8bb61b6cdc0978a6a99f8dfb2cc789a451378d054698441005ecbdb6 - md5: f9e5fbc24009179e8b0409624691758a - depends: - - __unix - license: ISC - purls: [] - size: 155907 - timestamp: 1759649036195 -- conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda - sha256: 837b795a2bb39b75694ba910c13c15fa4998d4bb2a622c214a6a5174b2ae53d1 - md5: 74784ee3d225fc3dca89edb635b4e5cc +- conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2025.11.12-hbd8a1cb_0.conda + sha256: b986ba796d42c9d3265602bc038f6f5264095702dd546c14bc684e60c385e773 + md5: f0991f0f84902f6b6009b4d2350a83aa depends: - __unix license: ISC purls: [] - size: 154402 - timestamp: 1754210968730 + size: 152432 + timestamp: 1762967197890 - conda: https://prefix.dev/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda sha256: 3bd6a391ad60e471de76c0e9db34986c4b5058587fbf2efa5a7f54645e28c2c7 md5: 09262e66b19567aff4f592fb53b28760 @@ -815,32 +778,22 @@ packages: purls: [] size: 896173 timestamp: 1741554795915 -- conda: https://prefix.dev/conda-forge/noarch/certifi-2025.10.5-pyhd8ed1ab_0.conda - sha256: 955bac31be82592093f6bc006e09822cd13daf52b28643c9a6abd38cd5f4a306 - md5: 257ae203f1d204107ba389607d375ded +- conda: https://prefix.dev/conda-forge/noarch/certifi-2025.11.12-pyhd8ed1ab_0.conda + sha256: 083a2bdad892ccf02b352ecab38ee86c3e610ba9a4b11b073ea769d55a115d32 + md5: 96a02a5c1a65470a7e4eedb644c872fd depends: - python >=3.10 license: ISC purls: - - pkg:pypi/certifi?source=hash-mapping - size: 160248 - timestamp: 1759648987029 -- conda: https://prefix.dev/conda-forge/noarch/certifi-2025.8.3-pyhd8ed1ab_0.conda - sha256: a1ad5b0a2a242f439608f22a538d2175cac4444b7b3f4e2b8c090ac337aaea40 - md5: 11f59985f49df4620890f3e746ed7102 - depends: - - python >=3.9 - license: ISC - purls: - pkg:pypi/certifi?source=compressed-mapping - size: 158692 - timestamp: 1754231530168 -- conda: https://prefix.dev/conda-forge/linux-64/cffi-1.17.1-py311h5b438cf_1.conda - sha256: bbd04c8729e6400fa358536b1007c1376cc396d569b71de10f1df7669d44170e - md5: 82e0123a459d095ac99c76d150ccdacf + size: 157131 + timestamp: 1762976260320 +- conda: https://prefix.dev/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda + sha256: 3ad13377356c86d3a945ae30e9b8c8734300925ef81a3cb0a9db0d755afbe7bb + md5: 3912e4373de46adafd8f1e97e4bd166b depends: - __glibc >=2.17,<3.0.a0 - - libffi >=3.4.6,<3.5.0a0 + - libffi >=3.5.2,<3.6.0a0 - libgcc >=14 - pycparser - python >=3.11,<3.12.0a0 @@ -848,15 +801,15 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/cffi?source=compressed-mapping - size: 303055 - timestamp: 1756808613387 -- conda: https://prefix.dev/conda-forge/osx-arm64/cffi-2.0.0-py311hcfc1310_0.conda - sha256: 207802a43cca5e81e1c267daabbb9b393d8c766f23883b3a2cb099d34eb51345 - md5: 419d91ef5b062ce19b3a513dcd566df8 + - pkg:pypi/cffi?source=hash-mapping + size: 303338 + timestamp: 1761202960110 +- conda: https://prefix.dev/conda-forge/osx-arm64/cffi-2.0.0-py311hd10dc20_1.conda + sha256: 1ffde698463d6e7ed571bdb85cb17bfc1d3a107c026d20047995512dcc2749ec + md5: 4d7f6780e36f18e7601811dddf3bbec5 depends: - __osx >=11.0 - - libffi >=3.4.6,<3.5.0a0 + - libffi >=3.5.2,<3.6.0a0 - pycparser - python >=3.11,<3.12.0a0 - python >=3.11,<3.12.0a0 *_cpython @@ -865,8 +818,8 @@ packages: license_family: MIT purls: - pkg:pypi/cffi?source=hash-mapping - size: 294021 - timestamp: 1758716481369 + size: 294848 + timestamp: 1761203196617 - conda: https://prefix.dev/conda-forge/noarch/cfgv-3.3.1-pyhd8ed1ab_1.conda sha256: d5696636733b3c301054b948cdd793f118efacce361d9bd4afb57d5980a9064f md5: 57df494053e17dce2ac3a0b33e1b2a2e @@ -878,21 +831,9 @@ packages: - pkg:pypi/cfgv?source=hash-mapping size: 12973 timestamp: 1734267180483 -- conda: https://prefix.dev/conda-forge/noarch/click-8.2.1-pyh707e725_0.conda - sha256: 8aee789c82d8fdd997840c952a586db63c6890b00e88c4fb6e80a38edd5f51c0 - md5: 94b550b8d3a614dbd326af798c7dfb40 - depends: - - __unix - - python >=3.10 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/click?source=hash-mapping - size: 87749 - timestamp: 1747811451319 -- conda: https://prefix.dev/conda-forge/noarch/click-8.3.0-pyh707e725_0.conda - sha256: c6567ebc27c4c071a353acaf93eb82bb6d9a6961e40692a359045a89a61d02c0 - md5: e76c4ba9e1837847679421b8d549b784 +- conda: https://prefix.dev/conda-forge/noarch/click-8.3.1-pyh707e725_0.conda + sha256: 970b12fb186c3451eee9dd0f10235aeb75fb570b0e9dc83250673c2f0b196265 + md5: 9ba00b39e03a0afb2b1cc0767d4c6175 depends: - __unix - python >=3.10 @@ -900,19 +841,19 @@ packages: license_family: BSD purls: - pkg:pypi/click?source=compressed-mapping - size: 91622 - timestamp: 1758270534287 -- conda: https://prefix.dev/conda-forge/noarch/cloudpickle-3.1.1-pyhd8ed1ab_0.conda - sha256: 21ecead7268241007bf65691610cd7314da68c1f88113092af690203b5780db5 - md5: 364ba6c9fb03886ac979b482f39ebb92 + size: 92604 + timestamp: 1763248639281 +- conda: https://prefix.dev/conda-forge/noarch/cloudpickle-3.1.2-pyhd8ed1ab_0.conda + sha256: 57050bd1bbac9e4be3728da4d33dee2168884d61d0ec51cd2ac72a1b34e11fc3 + md5: fcac5929097ba1f2a0e5b6ecaa13b253 depends: - - python >=3.9 + - python >=3.10 license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/cloudpickle?source=hash-mapping - size: 25870 - timestamp: 1736947650712 + - pkg:pypi/cloudpickle?source=compressed-mapping + size: 26621 + timestamp: 1762167702602 - conda: https://prefix.dev/conda-forge/linux-64/cmake-3.26.4-hcfe8598_0.conda sha256: 37533b572a676017704c989c392998c344e889010786d6555dccdfc524a8e238 md5: 1714cf0f0facaeb609a0846e4270aff2 @@ -967,14 +908,14 @@ packages: - pkg:pypi/colorama?source=hash-mapping size: 27011 timestamp: 1733218222191 -- conda: https://prefix.dev/conda-forge/linux-64/cryptography-45.0.7-py311h8488d03_1.conda - sha256: 644293db10382f9e6b8771d09b3dd17c53a027bdaf6b324644fdf2559ad69bc3 - md5: 85259057cb379cf9f1b8c95cb9b53d1b +- conda: https://prefix.dev/conda-forge/linux-64/cryptography-46.0.3-py311h8488d03_0.conda + sha256: 893d87bee341ce987fc8d461ff96c880d16568508318bbe524069ea3aa98599d + md5: 6bdc040b8f49f10d776ad2f9f5704e91 depends: - __glibc >=2.17,<3.0.a0 - - cffi >=1.12 + - cffi >=1.14 - libgcc >=14 - - openssl >=3.5.2,<4.0a0 + - openssl >=3.5.4,<4.0a0 - python >=3.11,<3.12.0a0 - python_abi 3.11.* *_cp311 constrains: @@ -983,8 +924,8 @@ packages: license_family: BSD purls: - pkg:pypi/cryptography?source=hash-mapping - size: 1659493 - timestamp: 1756843520631 + size: 1718616 + timestamp: 1760605259113 - conda: https://prefix.dev/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda sha256: 22053a5842ca8ee1cf8e1a817138cdb5e647eb2c46979f84153f6ad7bde73020 md5: 418c6ca5929a611cbd69204907a83995 @@ -1055,16 +996,29 @@ packages: - pkg:pypi/editables?source=hash-mapping size: 10828 timestamp: 1733208220327 -- conda: https://prefix.dev/conda-forge/linux-64/epoxy-1.5.10-h166bdaf_1.tar.bz2 - sha256: 1e58ee2ed0f4699be202f23d49b9644b499836230da7dd5b2f63e6766acff89e - md5: a089d06164afd2d511347d3f87214e0b +- conda: https://prefix.dev/conda-forge/linux-64/epoxy-1.5.10-hb03c661_2.conda + sha256: a5b51e491fec22bcc1765f5b2c8fff8a97428e9a5a7ee6730095fb9d091b0747 + md5: 057083b06ccf1c2778344b6dabace38b depends: - - libgcc-ng >=10.3.0 + - __glibc >=2.17,<3.0.a0 + - libdrm >=2.4.125,<2.5.0a0 + - libegl >=1.7.0,<2.0a0 + - libegl-devel + - libgcc >=14 + - libgl >=1.7.0,<2.0a0 + - libgl-devel + - libglx >=1.7.0,<2.0a0 + - libglx-devel + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxdamage >=1.1.6,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxxf86vm >=1.1.6,<2.0a0 license: MIT license_family: MIT purls: [] - size: 1440699 - timestamp: 1648505042260 + size: 411735 + timestamp: 1758743520805 - conda: https://prefix.dev/conda-forge/osx-arm64/epoxy-1.5.10-hc919400_2.conda sha256: ba685b87529c95a4bf9de140a33d703d57dc46b036e9586ed26890de65c1c0d5 md5: 3b87dabebe54c6d66a07b97b53ac5874 @@ -1086,29 +1040,29 @@ packages: - pkg:pypi/exceptiongroup?source=hash-mapping size: 21284 timestamp: 1746947398083 -- conda: https://prefix.dev/conda-forge/linux-64/expat-2.7.1-hecca717_0.conda - sha256: e981cf62a722f0eb4631ac7b786c288c03883fbc241fa98a276308fb69cb2c59 - md5: 6033d8c2bb9b460929d00ba54154614c +- conda: https://prefix.dev/conda-forge/linux-64/expat-2.7.3-hecca717_0.conda + sha256: c5d573e6831fb41177fb5ae0f1ee09caed55a868ec9887bc80ccc22c3e57b9b4 + md5: c81f6fa1865526f5ab1e6b669b3ee877 depends: - __glibc >=2.17,<3.0.a0 - - libexpat 2.7.1 hecca717_0 + - libexpat 2.7.3 hecca717_0 - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 140948 - timestamp: 1752719584725 -- conda: https://prefix.dev/conda-forge/osx-arm64/expat-2.7.1-hec049ff_0.conda - sha256: 8f2d1faeff1da40e66285711934e0d310d768720552452daa89b099aa8f82f29 - md5: 7888ca1ed7f0abef9442620dcf926e17 + size: 143991 + timestamp: 1763549744569 +- conda: https://prefix.dev/conda-forge/osx-arm64/expat-2.7.3-haf25636_0.conda + sha256: 43175c9c1f8a259776a215fe2a77c6a29cf79cc47ee1a98f5267ae47f904c9c8 + md5: 884f1698556805bc43c42e80c9c19f3d depends: - __osx >=11.0 - - libexpat 2.7.1 hec049ff_0 + - libexpat 2.7.3 haf25636_0 license: MIT license_family: MIT purls: [] - size: 127524 - timestamp: 1752719671694 + size: 131515 + timestamp: 1763550010595 - conda: https://prefix.dev/conda-forge/noarch/farama-notifications-0.0.4-pyhd8ed1ab_0.conda sha256: 8df190d75bac104c6c2317b13397eed9adfa6889b12405b0288ca2ca86855c06 md5: 61f63fcf1c2deddeae7a85a516d46c94 @@ -1120,16 +1074,6 @@ packages: - pkg:pypi/farama-notifications?source=hash-mapping size: 8406 timestamp: 1684258265351 -- conda: https://prefix.dev/conda-forge/noarch/filelock-3.19.1-pyhd8ed1ab_0.conda - sha256: 7a2497c775cc7da43b5e32fc5cf9f4e8301ca723f0eb7f808bbe01c6094a3693 - md5: 9c418d067409452b2e87e0016257da68 - depends: - - python >=3.9 - license: Unlicense - purls: - - pkg:pypi/filelock?source=compressed-mapping - size: 18003 - timestamp: 1755216353218 - conda: https://prefix.dev/conda-forge/noarch/filelock-3.20.0-pyhd8ed1ab_0.conda sha256: 19025a4078ff3940d97eb0da29983d5e0deac9c3e09b0eabf897daeaf9d1114e md5: 66b8b26023b8efdf8fcb23bac4b6325d @@ -1246,29 +1190,29 @@ packages: purls: [] size: 3667 timestamp: 1566974674465 -- conda: https://prefix.dev/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 - sha256: 53f23a3319466053818540bcdf2091f253cbdbab1e0e9ae7b9e509dcaa2a5e38 - md5: f766549260d6815b0c52253f1fb1bb29 +- conda: https://prefix.dev/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda + sha256: 54eea8469786bc2291cc40bca5f46438d3e062a399e8f53f013b6a9f50e98333 + md5: a7970cd949a077b7cb9696379d338681 depends: - - font-ttf-dejavu-sans-mono + - font-ttf-ubuntu - font-ttf-inconsolata + - font-ttf-dejavu-sans-mono - font-ttf-source-code-pro - - font-ttf-ubuntu license: BSD-3-Clause license_family: BSD purls: [] - size: 4102 - timestamp: 1566932280397 -- conda: https://prefix.dev/conda-forge/linux-64/freetype-2.13.3-ha770c72_1.conda - sha256: 7ef7d477c43c12a5b4cddcf048a83277414512d1116aba62ebadfa7056a7d84f - md5: 9ccd736d31e0c6e41f54e704e5312811 + size: 4059 + timestamp: 1762351264405 +- conda: https://prefix.dev/conda-forge/linux-64/freetype-2.14.1-ha770c72_0.conda + sha256: bf8e4dffe46f7d25dc06f31038cacb01672c47b9f45201f065b0f4d00ab0a83e + md5: 4afc585cd97ba8a23809406cd8a9eda8 depends: - - libfreetype 2.13.3 ha770c72_1 - - libfreetype6 2.13.3 h48d6fc4_1 + - libfreetype 2.14.1 ha770c72_0 + - libfreetype6 2.14.1 h73754d4_0 license: GPL-2.0-only OR FTL purls: [] - size: 172450 - timestamp: 1745369996765 + size: 173114 + timestamp: 1757945422243 - conda: https://prefix.dev/conda-forge/osx-arm64/freetype-2.14.1-hce30654_0.conda sha256: 14427aecd72e973a73d5f9dfd0e40b6bc3791d253de09b7bf233f6a9a190fd17 md5: 1ec9a1ee7a2c9339774ad9bb6fe6caec @@ -1298,9 +1242,9 @@ packages: purls: [] size: 59391 timestamp: 1757438897523 -- conda: https://prefix.dev/conda-forge/linux-64/gdk-pixbuf-2.44.1-h2b0a6b4_0.conda - sha256: b827285fe001806beeddcc30953d2bd07869aeb0efe4581d56432c92c06b0c48 - md5: 2935d9c0526277bd42373cf23d49d51f +- conda: https://prefix.dev/conda-forge/linux-64/gdk-pixbuf-2.44.4-h2b0a6b4_0.conda + sha256: f47222f58839bcc77c15f11a8814c1d8cb8080c5ca6ba83398a12b640fd3c85c + md5: c379d67c686fb83475c1a6ed41cc41ff depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -1308,12 +1252,12 @@ packages: - libjpeg-turbo >=3.1.0,<4.0a0 - liblzma >=5.8.1,<6.0a0 - libpng >=1.6.50,<1.7.0a0 - - libtiff >=4.7.0,<4.8.0a0 + - libtiff >=4.7.1,<4.8.0a0 license: LGPL-2.1-or-later license_family: LGPL purls: [] - size: 579596 - timestamp: 1757867209855 + size: 572093 + timestamp: 1761082340749 - conda: https://prefix.dev/conda-forge/osx-arm64/gdk-pixbuf-2.44.4-h7542897_0.conda sha256: 1164ba63360736439c6e50f2d390e93f04df86901e7711de41072a32d9b8bfc9 md5: 0b349c0400357e701cf2fa69371e5d39 @@ -1389,28 +1333,28 @@ packages: purls: [] size: 3748044 timestamp: 1751558602508 -- conda: https://prefix.dev/conda-forge/linux-64/glib-tools-2.86.0-hf516916_0.conda - sha256: b77316bd5c8680bde4e5a7ab7013c8f0f10c1702cc6c3b0fd0fac3923a31fec3 - md5: 1a8e49615381c381659de1bc6a3bf9ec +- conda: https://prefix.dev/conda-forge/linux-64/glib-tools-2.86.1-hf516916_2.conda + sha256: 743c57390c289c771a3bc90e27c817322a6dc518a3f00970caf2ee7b09421b46 + md5: b069da7bb5db4edd45e9f8887f10b52e depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - - libglib 2.86.0 h1fed272_0 + - libglib 2.86.1 h32235b2_2 license: LGPL-2.1-or-later purls: [] - size: 117284 - timestamp: 1757403341964 -- conda: https://prefix.dev/conda-forge/osx-arm64/glib-tools-2.86.0-hb9d6e3a_0.conda - sha256: 8d47509530193c3f29272fc7eb45ae0517537ae5a0d0628d9c7ecc0adc79ee05 - md5: 4b9d5cb3c1b584392b97be75d0a7d709 + size: 115896 + timestamp: 1762787507126 +- conda: https://prefix.dev/conda-forge/osx-arm64/glib-tools-2.86.1-hb9d6e3a_2.conda + sha256: 9356ad36d5a473385770e44a580a435eb7882d32cbe38994a88d8e6b59e1743d + md5: fa094eb162909927c6d5d480485c012c depends: - __osx >=11.0 - - libglib 2.86.0 h1bb475b_0 + - libglib 2.86.1 he69a767_2 - libintl >=0.25.1,<1.0a0 license: LGPL-2.1-or-later purls: [] - size: 102231 - timestamp: 1757404604900 + size: 100487 + timestamp: 1762789333153 - conda: https://prefix.dev/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda sha256: 25ba37da5c39697a77fce2c9a15e48cf0a84f1464ad2aafbe53d8357a9f6cc8c md5: 2cd94587f3a401ae05e03a6caf09539d @@ -1483,9 +1427,9 @@ packages: purls: [] size: 2201370 timestamp: 1754732518951 -- conda: https://prefix.dev/conda-forge/linux-64/gtk3-3.24.43-h0c6a113_5.conda - sha256: d36263cbcbce34ec463ce92bd72efa198b55d987959eab6210cc256a0e79573b - md5: 67d00e9cfe751cfe581726c5eff7c184 +- conda: https://prefix.dev/conda-forge/linux-64/gtk3-3.24.43-h993cebd_6.conda + sha256: 004688fbb2c479b200a6d85ef38c3129fcd4ce13537b7ee2371d962b372761c1 + md5: f9f33c65b20e6a61f21714785e3613ec depends: - __glibc >=2.17,<3.0.a0 - at-spi2-atk >=2.38.0,<3.0a0 @@ -1494,27 +1438,27 @@ packages: - epoxy >=1.5.10,<1.6.0a0 - fontconfig >=2.15.0,<3.0a0 - fonts-conda-ecosystem - - fribidi >=1.0.10,<2.0a0 - - gdk-pixbuf >=2.42.12,<3.0a0 + - fribidi >=1.0.16,<2.0a0 + - gdk-pixbuf >=2.44.4,<3.0a0 - glib-tools - - harfbuzz >=11.0.0,<12.0a0 + - harfbuzz >=11.5.1 - hicolor-icon-theme - libcups >=2.3.3,<2.4.0a0 - libcups >=2.3.3,<3.0a0 - - libexpat >=2.6.4,<3.0a0 - - libgcc >=13 - - libglib >=2.84.0,<3.0a0 - - liblzma >=5.6.4,<6.0a0 - - libxkbcommon >=1.8.1,<2.0a0 + - libexpat >=2.7.1,<3.0a0 + - libgcc >=14 + - libglib >=2.86.0,<3.0a0 + - liblzma >=5.8.1,<6.0a0 + - libxkbcommon >=1.12.2,<2.0a0 - libzlib >=1.3.1,<2.0a0 - - pango >=1.56.3,<2.0a0 - - wayland >=1.23.1,<2.0a0 + - pango >=1.56.4,<2.0a0 + - wayland >=1.24.0,<2.0a0 - xorg-libx11 >=1.8.12,<2.0a0 - xorg-libxcomposite >=0.4.6,<1.0a0 - xorg-libxcursor >=1.2.3,<2.0a0 - xorg-libxdamage >=1.1.6,<2.0a0 - xorg-libxext >=1.3.6,<2.0a0 - - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxfixes >=6.0.2,<7.0a0 - xorg-libxi >=1.8.2,<2.0a0 - xorg-libxinerama >=1.1.5,<1.2.0a0 - xorg-libxrandr >=1.5.4,<2.0a0 @@ -1522,32 +1466,32 @@ packages: license: LGPL-2.0-or-later license_family: LGPL purls: [] - size: 5585389 - timestamp: 1743405684985 -- conda: https://prefix.dev/conda-forge/osx-arm64/gtk3-3.24.43-h07173f4_5.conda - sha256: 9650ac1a02975ae0a3917443dc3c35ddc4d8e87a1cb04fda115af5f98e5d457c - md5: 8353369d4c2ecc5afd888405d3226fd9 + size: 5587108 + timestamp: 1761327349586 +- conda: https://prefix.dev/conda-forge/osx-arm64/gtk3-3.24.43-h5febe37_6.conda + sha256: bd66a3325bf3ce63ada3bf12eaafcfe036698741ee4bb595e83e5fdd3dba9f3d + md5: a99f96906158ebae5e3c0904bcd45145 depends: - __osx >=11.0 - atk-1.0 >=2.38.0 - cairo >=1.18.4,<2.0a0 - epoxy >=1.5.10,<1.6.0a0 - - fribidi >=1.0.10,<2.0a0 - - gdk-pixbuf >=2.42.12,<3.0a0 + - fribidi >=1.0.16,<2.0a0 + - gdk-pixbuf >=2.44.4,<3.0a0 - glib-tools - - harfbuzz >=11.0.0,<12.0a0 + - harfbuzz >=11.5.1 - hicolor-icon-theme - - libexpat >=2.6.4,<3.0a0 - - libglib >=2.84.0,<3.0a0 - - libintl >=0.23.1,<1.0a0 - - liblzma >=5.6.4,<6.0a0 + - libexpat >=2.7.1,<3.0a0 + - libglib >=2.86.0,<3.0a0 + - libintl >=0.25.1,<1.0a0 + - liblzma >=5.8.1,<6.0a0 - libzlib >=1.3.1,<2.0a0 - - pango >=1.56.3,<2.0a0 + - pango >=1.56.4,<2.0a0 license: LGPL-2.0-or-later license_family: LGPL purls: [] - size: 4792338 - timestamp: 1743406461562 + size: 4768791 + timestamp: 1761328318680 - conda: https://prefix.dev/conda-forge/linux-64/gts-0.7.6-h977cf35_4.conda sha256: b5cd16262fefb836f69dc26d879b6508d29f8a5c5948a966c47fe99e2e19c99b md5: 4d8df0b0db060d33c9a702ada998a8fe @@ -1632,29 +1576,29 @@ packages: - pkg:pypi/h2?source=compressed-mapping size: 95967 timestamp: 1756364871835 -- conda: https://prefix.dev/conda-forge/linux-64/harfbuzz-11.4.5-h15599e2_0.conda - sha256: 9d0d74858e8f8b76f6d3bf11a7390e6eb18eb743dd6e5fd7c4e9822634556f6d - md5: 1276ae4aa3832a449fcb4253c30da4bc +- conda: https://prefix.dev/conda-forge/linux-64/harfbuzz-12.2.0-h15599e2_0.conda + sha256: 6bd8b22beb7d40562b2889dc68232c589ff0d11a5ad3addd41a8570d11f039d9 + md5: b8690f53007e9b5ee2c2178dd4ac778c depends: - __glibc >=2.17,<3.0.a0 - cairo >=1.18.4,<2.0a0 - graphite2 >=1.3.14,<2.0a0 - icu >=75.1,<76.0a0 - libexpat >=2.7.1,<3.0a0 - - libfreetype >=2.13.3 - - libfreetype6 >=2.13.3 + - libfreetype >=2.14.1 + - libfreetype6 >=2.14.1 - libgcc >=14 - - libglib >=2.84.3,<3.0a0 + - libglib >=2.86.1,<3.0a0 - libstdcxx >=14 - libzlib >=1.3.1,<2.0a0 license: MIT license_family: MIT purls: [] - size: 2402438 - timestamp: 1756738217200 -- conda: https://prefix.dev/conda-forge/osx-arm64/harfbuzz-11.5.1-haf38c7b_0.conda - sha256: ceea9b35e8e81a0e345035f2e46574a213b7d3d7b2f8fdd0cb049490bddde6c2 - md5: effd4cec7d221d77cd937a83132f5b9e + size: 2411408 + timestamp: 1762372726141 +- conda: https://prefix.dev/conda-forge/osx-arm64/harfbuzz-12.2.0-haf38c7b_0.conda + sha256: 2f8d95fe1cb655fe3bac114062963f08cc77b31b042027ef7a04ebde3ce21594 + md5: 1c7ff9d458dd8220ac2ee71dd4af1be5 depends: - __osx >=11.0 - cairo >=1.18.4,<2.0a0 @@ -1664,13 +1608,13 @@ packages: - libexpat >=2.7.1,<3.0a0 - libfreetype >=2.14.1 - libfreetype6 >=2.14.1 - - libglib >=2.86.0,<3.0a0 + - libglib >=2.86.1,<3.0a0 - libzlib >=1.3.1,<2.0a0 license: MIT license_family: MIT purls: [] - size: 1514711 - timestamp: 1758640885114 + size: 1537764 + timestamp: 1762373922469 - conda: https://prefix.dev/conda-forge/noarch/hatch-1.14.1-pyhd8ed1ab_0.conda sha256: d245185287bdf5d3c808267aebda2cb7fbce779099493f92e368f813e6a157d4 md5: 82f74ce5f4548c3627ed52dfac9da8ca @@ -1822,18 +1766,6 @@ packages: purls: [] size: 11857802 timestamp: 1720853997952 -- conda: https://prefix.dev/conda-forge/noarch/identify-2.6.14-pyhd8ed1ab_0.conda - sha256: b7fc614777da38244ff36da51f9417822d6507a7b6a8da27aba579490941d160 - md5: 34a8172d191193030438d7b30bcdeaf5 - depends: - - python >=3.10 - - ukkonen - license: MIT - license_family: MIT - purls: - - pkg:pypi/identify?source=compressed-mapping - size: 79065 - timestamp: 1757209085517 - conda: https://prefix.dev/conda-forge/noarch/identify-2.6.15-pyhd8ed1ab_0.conda sha256: 32d5007d12e5731867908cbf5345f5cd44a6c8755a2e8e63e15a184826a51f82 md5: 25f954b7dae6dd7b0dc004dab74f1ce9 @@ -1846,17 +1778,6 @@ packages: - pkg:pypi/identify?source=hash-mapping size: 79151 timestamp: 1759437561529 -- conda: https://prefix.dev/conda-forge/noarch/idna-3.10-pyhd8ed1ab_1.conda - sha256: d7a472c9fd479e2e8dcb83fb8d433fce971ea369d704ece380e876f9c3494e87 - md5: 39a4f67be3286c86d696df570b1201b7 - depends: - - python >=3.9 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/idna?source=hash-mapping - size: 49765 - timestamp: 1733211921194 - conda: https://prefix.dev/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda sha256: ae89d0299ada2a3162c2614a9d26557a92aa6a77120ce142f8e0109bbf0342b0 md5: 53abe63df7e10a6ba605dc5f9f961d36 @@ -1865,7 +1786,7 @@ packages: license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/idna?source=compressed-mapping + - pkg:pypi/idna?source=hash-mapping size: 50721 timestamp: 1760286526795 - conda: https://prefix.dev/conda-forge/noarch/importlib-metadata-8.7.0-pyhe01879c_1.conda @@ -1895,17 +1816,6 @@ packages: - pkg:pypi/importlib-resources?source=hash-mapping size: 33781 timestamp: 1736252433366 -- conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.0.0-pyhd8ed1ab_1.conda - sha256: 0ec8f4d02053cd03b0f3e63168316530949484f80e16f5e2fb199a1d117a89ca - md5: 6837f3eff7dcea42ecd714ce1ac2b108 - depends: - - python >=3.9 - license: MIT - license_family: MIT - purls: - - pkg:pypi/iniconfig?source=hash-mapping - size: 11474 - timestamp: 1733223232820 - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda sha256: e1a9e3b1c8fe62dc3932a616c284b5d8cbe3124bbfbedcf4ce5c828cb166ee19 md5: 9614359868482abba1bd15ce465e3c42 @@ -1990,9 +1900,9 @@ packages: - pkg:pypi/jeepney?source=hash-mapping size: 40015 timestamp: 1740828380668 -- conda: https://prefix.dev/conda-forge/noarch/keyring-25.6.0-pyh534df25_0.conda - sha256: c8b436fa9853bf8b836c96afbb7684a04955b80b37f5d5285fd836b6a8566cc5 - md5: d2c0c5bda93c249f877c7fceea9e63af +- conda: https://prefix.dev/conda-forge/noarch/keyring-25.7.0-pyh534df25_0.conda + sha256: 9def5c6fb3b3b4952a4f6b55a019b5c7065b592682b84710229de5a0b73f6364 + md5: c88f9579d08eb4031159f03640714ce3 depends: - __osx - importlib-metadata >=4.11.4 @@ -2000,16 +1910,16 @@ packages: - jaraco.classes - jaraco.context - jaraco.functools - - python >=3.9 + - python >=3.10 license: MIT license_family: MIT purls: - pkg:pypi/keyring?source=hash-mapping - size: 37280 - timestamp: 1735210369348 -- conda: https://prefix.dev/conda-forge/noarch/keyring-25.6.0-pyha804496_0.conda - sha256: b6f57c17cf098022c32fe64e85e9615d427a611c48a5947cdfc357490210a124 - md5: cdd58ab99c214b55d56099108a914282 + size: 37924 + timestamp: 1763320995459 +- conda: https://prefix.dev/conda-forge/noarch/keyring-25.7.0-pyha804496_0.conda + sha256: 010718b1b1a35ce72782d38e6d6b9495d8d7d0dbea9a3e42901d030ff2189545 + md5: 9eeb0eaf04fa934808d3e070eebbe630 depends: - __linux - importlib-metadata >=4.11.4 @@ -2018,14 +1928,14 @@ packages: - jaraco.context - jaraco.functools - jeepney >=0.4.2 - - python >=3.9 + - python >=3.10 - secretstorage >=3.2 license: MIT license_family: MIT purls: - - pkg:pypi/keyring?source=hash-mapping - size: 36985 - timestamp: 1735210286595 + - pkg:pypi/keyring?source=compressed-mapping + size: 37717 + timestamp: 1763320674488 - conda: https://prefix.dev/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 md5: b38117a3c920364aff79f870c984b4a3 @@ -2083,18 +1993,19 @@ packages: purls: [] size: 528805 timestamp: 1664996399305 -- conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda - sha256: 1a620f27d79217c1295049ba214c2f80372062fd251b569e9873d4a953d27554 - md5: 0be7c6e070c19105f966d3758448d018 +- conda: https://prefix.dev/conda-forge/linux-64/ld_impl_linux-64-2.45-h1aa0949_0.conda + sha256: 32321d38b8785ef8ddcfef652ee370acee8d944681014d47797a18637ff16854 + md5: 1450224b3e7d17dfeb985364b77a4d47 depends: - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 constrains: - - binutils_impl_linux-64 2.44 + - binutils_impl_linux-64 2.45 license: GPL-3.0-only license_family: GPL purls: [] - size: 676044 - timestamp: 1752032747103 + size: 753744 + timestamp: 1763060439129 - pypi: https://files.pythonhosted.org/packages/fb/06/6a7c30c3519181263e1bbf0cbea67ef4a43a64443ee16717c7d760214943/lenses-1.2.0-py3-none-any.whl name: lenses version: 1.2.0 @@ -2207,84 +2118,84 @@ packages: purls: [] size: 110723 timestamp: 1756124882419 -- conda: https://prefix.dev/conda-forge/linux-64/libblas-3.9.0-35_h59b9bed_openblas.conda - build_number: 35 - sha256: 83d0755acd486660532003bc2562223504b57732bc7e250985391ce335692cf7 - md5: eaf80af526daf5745295d9964c2bd3cf +- conda: https://prefix.dev/conda-forge/linux-64/libblas-3.11.0-1_h4a7cf45_openblas.conda + build_number: 1 + sha256: a36d1230c435d9b06c3bbd1c5c32c695bc341a413719d6e8c4bb6574818f46ea + md5: 8b39e1ae950f1b54a3959c58ca2c32b8 depends: - libopenblas >=0.3.30,<0.3.31.0a0 - libopenblas >=0.3.30,<1.0a0 constrains: - - blas 2.135 openblas - - liblapack 3.9.0 35*_openblas - - libcblas 3.9.0 35*_openblas - - liblapacke 3.9.0 35*_openblas - - mkl <2025 + - liblapack 3.11.0 1*_openblas + - libcblas 3.11.0 1*_openblas + - mkl <2026 + - blas 2.301 openblas + - liblapacke 3.11.0 1*_openblas license: BSD-3-Clause license_family: BSD purls: [] - size: 16937 - timestamp: 1757002815691 -- conda: https://prefix.dev/conda-forge/osx-arm64/libblas-3.9.0-37_h51639a9_openblas.conda - build_number: 37 - sha256: 544f935351201a4bea7e1dae0b240ce619febf56655724c64481ec694293bc64 - md5: 675aec03581d97a77f7bb47e99fed4b4 + size: 18492 + timestamp: 1763447017981 +- conda: https://prefix.dev/conda-forge/osx-arm64/libblas-3.11.0-1_h51639a9_openblas.conda + build_number: 1 + sha256: 7096038e2231bfe315e7e5d3faba2371b70f9d6d897e065afd085781304dc8d1 + md5: 379254bdc34eec0bd4464935c3bff8ba depends: - libopenblas >=0.3.30,<0.3.31.0a0 - libopenblas >=0.3.30,<1.0a0 constrains: - - liblapacke 3.9.0 37*_openblas - - blas 2.137 openblas - - mkl <2025 - - liblapack 3.9.0 37*_openblas - - libcblas 3.9.0 37*_openblas + - blas 2.301 openblas + - liblapacke 3.11.0 1*_openblas + - liblapack 3.11.0 1*_openblas + - libcblas 3.11.0 1*_openblas + - mkl <2026 license: BSD-3-Clause license_family: BSD purls: [] - size: 17647 - timestamp: 1760213578751 -- conda: https://prefix.dev/conda-forge/linux-64/libcap-2.75-h39aace5_0.conda - sha256: 9c84448305e7c9cc44ccec7757cf5afcb5a021f4579aa750a1fa6ea398783950 - md5: c44c16d6976d2aebbd65894d7741e67e + size: 18675 + timestamp: 1763447903446 +- conda: https://prefix.dev/conda-forge/linux-64/libcap-2.77-h3ff7636_0.conda + sha256: 9517cce5193144af0fcbf19b7bd67db0a329c2cc2618f28ffecaa921a1cbe9d3 + md5: 09c264d40c67b82b49a3f3b89037bd2e depends: - __glibc >=2.17,<3.0.a0 - - attr >=2.5.1,<2.6.0a0 - - libgcc >=13 + - attr >=2.5.2,<2.6.0a0 + - libgcc >=14 license: BSD-3-Clause license_family: BSD purls: [] - size: 120375 - timestamp: 1741176638215 -- conda: https://prefix.dev/conda-forge/linux-64/libcblas-3.9.0-35_he106b2a_openblas.conda - build_number: 35 - sha256: 6f296f1567a7052c0f8b9527f74cfebc5418dbbae6dcdbae8659963f8ae7f48e - md5: e62d58d32431dabed236c860dfa566ca + size: 121429 + timestamp: 1762349484074 +- conda: https://prefix.dev/conda-forge/linux-64/libcblas-3.11.0-1_h0358290_openblas.conda + build_number: 1 + sha256: f39c69450d14049463a15adfffa01447cfe9e9497e323800d747ee828ae43a2b + md5: a670bff9eb7963ea41b4e09a4e4ab608 depends: - - libblas 3.9.0 35_h59b9bed_openblas + - libblas 3.11.0 1_h4a7cf45_openblas constrains: - - blas 2.135 openblas - - liblapack 3.9.0 35*_openblas - - liblapacke 3.9.0 35*_openblas + - blas 2.301 openblas + - liblapack 3.11.0 1*_openblas + - liblapacke 3.11.0 1*_openblas license: BSD-3-Clause license_family: BSD purls: [] - size: 16900 - timestamp: 1757002826333 -- conda: https://prefix.dev/conda-forge/osx-arm64/libcblas-3.9.0-37_hb0561ab_openblas.conda - build_number: 37 - sha256: 911a01cac0c76d52628fdfe2aecfa010b4145af630ec23fe3fefa7a4c8050a57 - md5: 33ab91e02a34879065d03bb010eb6bf1 + size: 18491 + timestamp: 1763447025579 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcblas-3.11.0-1_hb0561ab_openblas.conda + build_number: 1 + sha256: 816592d4f39a30db77b5de45e532b6f536f740d333840af21fcf6daf2f0b0c18 + md5: f2b9d50745b55f4a837b333e69b5974a depends: - - libblas 3.9.0 37_h51639a9_openblas + - libblas 3.11.0 1_h51639a9_openblas constrains: - - liblapacke 3.9.0 37*_openblas - - blas 2.137 openblas - - liblapack 3.9.0 37*_openblas + - blas 2.301 openblas + - liblapacke 3.11.0 1*_openblas + - liblapack 3.11.0 1*_openblas license: BSD-3-Clause license_family: BSD purls: [] - size: 17639 - timestamp: 1760213591611 + size: 18671 + timestamp: 1763447915947 - conda: https://prefix.dev/conda-forge/linux-64/libccd-double-2.1-h59595ed_3.conda sha256: 4695ce68eda595b4f53146bea1096a9f2e0d33290618ba83a246b5ed8871ebc9 md5: 6a3d962d34385e0a511b859d679f6ea2 @@ -2324,26 +2235,26 @@ packages: purls: [] size: 4523621 timestamp: 1749905341688 -- conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.14.1-h332b0f4_0.conda - sha256: b6c5cf340a4f80d70d64b3a29a7d9885a5918d16a5cb952022820e6d3e79dc8b - md5: 45f6713cb00f124af300342512219182 +- conda: https://prefix.dev/conda-forge/linux-64/libcurl-8.17.0-h4e3cde8_0.conda + sha256: 100e29ca864c32af15a5cc354f502d07b2600218740fdf2439fa7d66b50b3529 + md5: 01e149d4a53185622dc2e788281961f2 depends: - __glibc >=2.17,<3.0.a0 - krb5 >=1.21.3,<1.22.0a0 - - libgcc >=13 - - libnghttp2 >=1.64.0,<2.0a0 + - libgcc >=14 + - libnghttp2 >=1.67.0,<2.0a0 - libssh2 >=1.11.1,<2.0a0 - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.0,<4.0a0 + - openssl >=3.5.4,<4.0a0 - zstd >=1.5.7,<1.6.0a0 license: curl license_family: MIT purls: [] - size: 449910 - timestamp: 1749033146806 -- conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.16.0-hdece5d2_0.conda - sha256: f20ce8db8c62f1cdf4d7a9f92cabcc730b1212a7165f4b085e45941cc747edac - md5: 0537c38a90d179dcb3e46727ccc5bcc1 + size: 460366 + timestamp: 1762333743748 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcurl-8.17.0-hdece5d2_0.conda + sha256: 2980c5de44ac3ca2ecbd4a00756da1648ea2945d9e4a2ad9f216c7787df57f10 + md5: 791003efe92c17ed5949b309c61a5ab1 depends: - __osx >=11.0 - krb5 >=1.21.3,<1.22.0a0 @@ -2355,39 +2266,39 @@ packages: license: curl license_family: MIT purls: [] - size: 394279 - timestamp: 1760977967042 -- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.4-hf598326_0.conda - sha256: df55e80dda21f2581366f66cf18a6c11315d611f6fb01e56011c5199f983c0d9 - md5: 6002a2ba796f1387b6a5c6d77051d1db + size: 394183 + timestamp: 1762334288445 +- conda: https://prefix.dev/conda-forge/osx-arm64/libcxx-21.1.6-hf598326_0.conda + sha256: 6c8d5c50f398035c39f118a6decf91b11d2461c88aef99f81e5c5de200d2a7fa + md5: 3ea79e55a64bff6c3cbd4588c89a527a depends: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache purls: [] - size: 567892 - timestamp: 1761043967532 -- conda: https://prefix.dev/conda-forge/linux-64/libdeflate-1.24-h86f0d12_0.conda - sha256: 8420748ea1cc5f18ecc5068b4f24c7a023cc9b20971c99c824ba10641fb95ddf - md5: 64f0c503da58ec25ebd359e4d990afa8 + size: 569823 + timestamp: 1763470498512 +- conda: https://prefix.dev/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda + sha256: aa8e8c4be9a2e81610ddf574e05b64ee131fab5e0e3693210c9d6d2fba32c680 + md5: 6c77a605a7a689d17d4819c0f8ac9a00 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 72573 - timestamp: 1747040452262 -- conda: https://prefix.dev/conda-forge/osx-arm64/libdeflate-1.24-h5773f1b_0.conda - sha256: 417d52b19c679e1881cce3f01cad3a2d542098fa2d6df5485aac40f01aede4d1 - md5: 3baf58a5a87e7c2f4d243ce2f8f2fe5c + size: 73490 + timestamp: 1761979956660 +- conda: https://prefix.dev/conda-forge/osx-arm64/libdeflate-1.25-hc11a715_0.conda + sha256: 5e0b6961be3304a5f027a8c00bd0967fc46ae162cffb7553ff45c70f51b8314c + md5: a6130c709305cd9828b4e1bd9ba0000c depends: - __osx >=11.0 license: MIT license_family: MIT purls: [] - size: 54790 - timestamp: 1747040549847 + size: 55420 + timestamp: 1761980066242 - conda: https://prefix.dev/conda-forge/linux-64/libdrm-2.4.125-hb03c661_1.conda sha256: c076a213bd3676cc1ef22eeff91588826273513ccc6040d9bea68bccdc849501 md5: 9314bc5a1fe7d1044dc9dfd3ef400535 @@ -2435,6 +2346,18 @@ packages: purls: [] size: 44840 timestamp: 1731330973553 +- conda: https://prefix.dev/conda-forge/linux-64/libegl-devel-1.7.0-ha4b6fd6_2.conda + sha256: f6e7095260305dc05238062142fb8db4b940346329b5b54894a90610afa6749f + md5: b513eb83b3137eca1192c34bf4f013a7 + depends: + - __glibc >=2.17,<3.0.a0 + - libegl 1.7.0 ha4b6fd6_2 + - libgl-devel 1.7.0 ha4b6fd6_2 + - xorg-libx11 + license: LicenseRef-libglvnd + purls: [] + size: 30380 + timestamp: 1731331017249 - conda: https://prefix.dev/conda-forge/linux-64/libev-4.33-hd590300_2.conda sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 md5: 172bf1cd1ff8629f2b1179945ed45055 @@ -2453,52 +2376,42 @@ packages: purls: [] size: 107458 timestamp: 1702146414478 -- conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda - sha256: da2080da8f0288b95dd86765c801c6e166c4619b910b11f9a8446fb852438dc2 - md5: 4211416ecba1866fab0c6470986c22d6 +- conda: https://prefix.dev/conda-forge/linux-64/libexpat-2.7.3-hecca717_0.conda + sha256: 1e1b08f6211629cbc2efe7a5bca5953f8f6b3cae0eeb04ca4dacee1bd4e2db2f + md5: 8b09ae86839581147ef2e5c5e229d164 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 constrains: - - expat 2.7.1.* + - expat 2.7.3.* license: MIT license_family: MIT purls: [] - size: 74811 - timestamp: 1752719572741 -- conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.1-hec049ff_0.conda - sha256: 8fbb17a56f51e7113ed511c5787e0dec0d4b10ef9df921c4fd1cccca0458f648 - md5: b1ca5f21335782f71a8bd69bdc093f67 + size: 76643 + timestamp: 1763549731408 +- conda: https://prefix.dev/conda-forge/osx-arm64/libexpat-2.7.3-haf25636_0.conda + sha256: fce22610ecc95e6d149e42a42fbc3cc9d9179bd4eb6232639a60f06e080eec98 + md5: b79875dbb5b1db9a4a22a4520f918e1a depends: - __osx >=11.0 constrains: - - expat 2.7.1.* + - expat 2.7.3.* license: MIT license_family: MIT purls: [] - size: 65971 - timestamp: 1752719657566 -- conda: https://prefix.dev/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda - sha256: 764432d32db45466e87f10621db5b74363a9f847d2b8b1f9743746cd160f06ab - md5: ede4673863426c0883c0063d853bbd85 + size: 67800 + timestamp: 1763549994166 +- conda: https://prefix.dev/conda-forge/linux-64/libffi-3.5.2-h9ec8514_0.conda + sha256: 25cbdfa65580cfab1b8d15ee90b4c9f1e0d72128f1661449c9a999d341377d54 + md5: 35f29eec58405aaf55e01cb470d8c26a depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - license: MIT - license_family: MIT - purls: [] - size: 57433 - timestamp: 1743434498161 -- conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.4.6-h1da3d7d_1.conda - sha256: c6a530924a9b14e193ea9adfe92843de2a806d1b7dbfd341546ece9653129e60 - md5: c215a60c2935b517dcda8cad4705734d - depends: - - __osx >=11.0 + - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 39839 - timestamp: 1743434670405 + size: 57821 + timestamp: 1760295480630 - conda: https://prefix.dev/conda-forge/osx-arm64/libffi-3.5.2-he5f378a_0.conda sha256: 9b8acdf42df61b7bfe8bdc545c016c29e61985e79748c64ad66df47dbc2e295f md5: 411ff7cd5d1472bba0f55c0faf04453b @@ -2536,15 +2449,15 @@ packages: purls: [] size: 314408 timestamp: 1687766236790 -- conda: https://prefix.dev/conda-forge/linux-64/libfreetype-2.13.3-ha770c72_1.conda - sha256: 7be9b3dac469fe3c6146ff24398b685804dfc7a1de37607b84abd076f57cc115 - md5: 51f5be229d83ecd401fb369ab96ae669 +- conda: https://prefix.dev/conda-forge/linux-64/libfreetype-2.14.1-ha770c72_0.conda + sha256: 4641d37faeb97cf8a121efafd6afd040904d4bca8c46798122f417c31d5dfbec + md5: f4084e4e6577797150f9b04a4560ceb0 depends: - - libfreetype6 >=2.13.3 + - libfreetype6 >=2.14.1 license: GPL-2.0-only OR FTL purls: [] - size: 7693 - timestamp: 1745369988361 + size: 7664 + timestamp: 1757945417134 - conda: https://prefix.dev/conda-forge/osx-arm64/libfreetype-2.14.1-hce30654_0.conda sha256: 9de25a86066f078822d8dd95a83048d7dc2897d5d655c0e04a8a54fca13ef1ef md5: f35fb38e89e2776994131fbf961fa44b @@ -2554,20 +2467,20 @@ packages: purls: [] size: 7810 timestamp: 1757947168537 -- conda: https://prefix.dev/conda-forge/linux-64/libfreetype6-2.13.3-h48d6fc4_1.conda - sha256: 7759bd5c31efe5fbc36a7a1f8ca5244c2eabdbeb8fc1bee4b99cf989f35c7d81 - md5: 3c255be50a506c50765a93a6644f32fe +- conda: https://prefix.dev/conda-forge/linux-64/libfreetype6-2.14.1-h73754d4_0.conda + sha256: 4a7af818a3179fafb6c91111752954e29d3a2a950259c14a2fc7ba40a8b03652 + md5: 8e7251989bca326a28f4a5ffbd74557a depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libpng >=1.6.47,<1.7.0a0 + - libgcc >=14 + - libpng >=1.6.50,<1.7.0a0 - libzlib >=1.3.1,<2.0a0 constrains: - - freetype >=2.13.3 + - freetype >=2.14.1 license: GPL-2.0-only OR FTL purls: [] - size: 380134 - timestamp: 1745369987697 + size: 386739 + timestamp: 1757945416744 - conda: https://prefix.dev/conda-forge/osx-arm64/libfreetype6-2.14.1-h6da58f4_0.conda sha256: cc4aec4c490123c0f248c1acd1aeab592afb6a44b1536734e20937cda748f7cd md5: 6d4ede03e2a8e20eb51f7f681d2a2550 @@ -2581,41 +2494,30 @@ packages: purls: [] size: 346703 timestamp: 1757947166116 -- conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda - sha256: 0caed73aac3966bfbf5710e06c728a24c6c138605121a3dacb2e03440e8baa6a - md5: 264fbfba7fb20acf3b29cde153e345ce +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-15.2.0-h767d61c_7.conda + sha256: 08f9b87578ab981c7713e4e6a7d935e40766e10691732bba376d4964562bcb45 + md5: c0374badb3a5d4b1372db28d19462c53 depends: - __glibc >=2.17,<3.0.a0 - _openmp_mutex >=4.5 constrains: - - libgomp 15.1.0 h767d61c_5 - - libgcc-ng ==15.1.0=*_5 + - libgomp 15.2.0 h767d61c_7 + - libgcc-ng ==15.2.0=*_7 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 824191 - timestamp: 1757042543820 -- conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda - sha256: f54bb9c3be12b24be327f4c1afccc2969712e0b091cdfbd1d763fb3e61cda03f - md5: 069afdf8ea72504e48d23ae1171d951c + size: 822552 + timestamp: 1759968052178 +- conda: https://prefix.dev/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_7.conda + sha256: 2045066dd8e6e58aaf5ae2b722fb6dfdbb57c862b5f34ac7bfb58c40ef39b6ad + md5: 280ea6eee9e2ddefde25ff799c4f0363 depends: - - libgcc 15.1.0 h767d61c_5 + - libgcc 15.2.0 h767d61c_7 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 29187 - timestamp: 1757042549554 -- conda: https://prefix.dev/conda-forge/linux-64/libgcrypt-lib-1.11.1-hb9d3cd8_0.conda - sha256: dc9c7d7a6c0e6639deee6fde2efdc7e119e7739a6b229fa5f9049a449bae6109 - md5: 8504a291085c9fb809b66cabd5834307 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libgpg-error >=1.55,<2.0a0 - license: LGPL-2.1-or-later - purls: [] - size: 590353 - timestamp: 1747060639058 + size: 29313 + timestamp: 1759968065504 - conda: https://prefix.dev/conda-forge/linux-64/libgd-2.3.3-h6f5c62b_11.conda sha256: 19e5be91445db119152217e8e8eec4fd0499d854acc7d8062044fb55a70971cd md5: 68fc66282364981589ef36868b1a7c78 @@ -2708,18 +2610,18 @@ packages: purls: [] size: 37894 timestamp: 1751558502415 -- conda: https://prefix.dev/conda-forge/linux-64/libgfortran-15.1.0-h69a702a_5.conda - sha256: 4c1a526198d0d62441549fdfd668cc8e18e77609da1e545bdcc771dd8dc6a990 - md5: 0c91408b3dec0b97e8a3c694845bd63b +- conda: https://prefix.dev/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_7.conda + sha256: 9ca24328e31c8ef44a77f53104773b9fe50ea8533f4c74baa8489a12de916f02 + md5: 8621a450add4e231f676646880703f49 depends: - - libgfortran5 15.1.0 hcea5267_5 + - libgfortran5 15.2.0 hcd61629_7 constrains: - - libgfortran-ng ==15.1.0=*_5 + - libgfortran-ng ==15.2.0=*_7 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 29169 - timestamp: 1757042575979 + size: 29275 + timestamp: 1759968110483 - conda: https://prefix.dev/conda-forge/osx-arm64/libgfortran-15.2.0-hfcf01ff_1.conda sha256: e9a5d1208b9dc0b576b35a484d527d9b746c4e65620e0d77c44636033b2245f0 md5: f699348e3f4f924728e33551b1920f79 @@ -2730,19 +2632,19 @@ packages: purls: [] size: 134016 timestamp: 1759712902814 -- conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda - sha256: 9d06adc6d8e8187ddc1cad87525c690bc8202d8cb06c13b76ab2fc80a35ed565 - md5: fbd4008644add05032b6764807ee2cba +- conda: https://prefix.dev/conda-forge/linux-64/libgfortran5-15.2.0-hcd61629_7.conda + sha256: e93ceda56498d98c9f94fedec3e2d00f717cbedfc97c49be0e5a5828802f2d34 + md5: f116940d825ffc9104400f0d7f1a4551 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=15.1.0 + - libgcc >=15.2.0 constrains: - - libgfortran 15.1.0 + - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 1564589 - timestamp: 1757042559498 + size: 1572758 + timestamp: 1759968082504 - conda: https://prefix.dev/conda-forge/osx-arm64/libgfortran5-15.2.0-h742603c_1.conda sha256: 18808697013a625ca876eeee3d86ee5b656f17c391eca4a4bc70867717cc5246 md5: afccf412b03ce2f309f875ff88419173 @@ -2766,38 +2668,49 @@ packages: purls: [] size: 134712 timestamp: 1731330998354 -- conda: https://prefix.dev/conda-forge/linux-64/libglib-2.86.0-h1fed272_0.conda - sha256: 33336bd55981be938f4823db74291e1323454491623de0be61ecbe6cf3a4619c - md5: b8e4c93f4ab70c3b6f6499299627dbdc +- conda: https://prefix.dev/conda-forge/linux-64/libgl-devel-1.7.0-ha4b6fd6_2.conda + sha256: e281356c0975751f478c53e14f3efea6cd1e23c3069406d10708d6c409525260 + md5: 53e7cbb2beb03d69a478631e23e340e9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgl 1.7.0 ha4b6fd6_2 + - libglx-devel 1.7.0 ha4b6fd6_2 + license: LicenseRef-libglvnd + purls: [] + size: 113911 + timestamp: 1731331012126 +- conda: https://prefix.dev/conda-forge/linux-64/libglib-2.86.1-h32235b2_2.conda + sha256: fc82277d0d6340743732c48dcbac3f4e9ee36902649a7d9a02622b0713ce3666 + md5: 986dcf488a1aced411da84753d93d078 depends: - __glibc >=2.17,<3.0.a0 - - libffi >=3.4.6,<3.5.0a0 + - libffi >=3.5.2,<3.6.0a0 - libgcc >=14 - libiconv >=1.18,<2.0a0 - libzlib >=1.3.1,<2.0a0 - pcre2 >=10.46,<10.47.0a0 constrains: - - glib 2.86.0 *_0 + - glib 2.86.1 *_2 license: LGPL-2.1-or-later purls: [] - size: 3978602 - timestamp: 1757403291664 -- conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.86.0-h1bb475b_0.conda - sha256: 92d17f998e14218810493c9190c8721bf7f7f006bfc5c00dbba1cede83c02f1a - md5: 9e065148e6013b7d7cae64ed01ab7081 + size: 3933707 + timestamp: 1762787455198 +- conda: https://prefix.dev/conda-forge/osx-arm64/libglib-2.86.1-he69a767_2.conda + sha256: ea49abd747b91cddf555f4ccd184cee8c1916363a78d4a7fe24b24d1163423c6 + md5: 6d6f8c7d3a52e2c193fb2f9ba2e0ef0b depends: - __osx >=11.0 - - libffi >=3.4.6,<3.5.0a0 + - libffi >=3.5.2,<3.6.0a0 - libiconv >=1.18,<2.0a0 - libintl >=0.25.1,<1.0a0 - libzlib >=1.3.1,<2.0a0 - pcre2 >=10.46,<10.47.0a0 constrains: - - glib 2.86.0 *_0 + - glib 2.86.1 *_2 license: LGPL-2.1-or-later purls: [] - size: 3701880 - timestamp: 1757404501093 + size: 3661248 + timestamp: 1762789184977 - conda: https://prefix.dev/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda sha256: 1175f8a7a0c68b7f81962699751bb6574e6f07db4c9f72825f978e3016f46850 md5: 434ca7e50e40f4918ab701e3facd59a0 @@ -2818,28 +2731,28 @@ packages: purls: [] size: 75504 timestamp: 1731330988898 -- conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda - sha256: 125051d51a8c04694d0830f6343af78b556dd88cc249dfec5a97703ebfb1832d - md5: dcd5ff1940cd38f6df777cac86819d60 +- conda: https://prefix.dev/conda-forge/linux-64/libglx-devel-1.7.0-ha4b6fd6_2.conda + sha256: 0a930e0148ab6e61089bbcdba25a2e17ee383e7de82e7af10cc5c12c82c580f3 + md5: 27ac5ae872a21375d980bd4a6f99edf3 depends: - __glibc >=2.17,<3.0.a0 - license: GPL-3.0-only WITH GCC-exception-3.1 - license_family: GPL + - libglx 1.7.0 ha4b6fd6_2 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-xorgproto + license: LicenseRef-libglvnd purls: [] - size: 447215 - timestamp: 1757042483384 -- conda: https://prefix.dev/conda-forge/linux-64/libgpg-error-1.55-h3f2d84a_0.conda - sha256: 697334de4786a1067ea86853e520c64dd72b11a05137f5b318d8a444007b5e60 - md5: 2bd47db5807daade8500ed7ca4c512a4 + size: 26388 + timestamp: 1731331003255 +- conda: https://prefix.dev/conda-forge/linux-64/libgomp-15.2.0-h767d61c_7.conda + sha256: e9fb1c258c8e66ee278397b5822692527c5f5786d372fe7a869b900853f3f5ca + md5: f7b4d76975aac7e5d9e6ad13845f92fe depends: - - libstdcxx >=13 - - libgcc >=13 - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - license: LGPL-2.1-only + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL purls: [] - size: 312184 - timestamp: 1745575272035 + size: 447919 + timestamp: 1759967942498 - conda: https://prefix.dev/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f md5: 915f5995e94f60e9a4826e0b0920ee88 @@ -2880,59 +2793,59 @@ packages: purls: [] size: 40340 timestamp: 1751558481257 -- conda: https://prefix.dev/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda - sha256: 98b399287e27768bf79d48faba8a99a2289748c65cd342ca21033fab1860d4a4 - md5: 9fa334557db9f63da6c9285fd2a48638 +- conda: https://prefix.dev/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda + sha256: cc9aba923eea0af8e30e0f94f2ad7156e2984d80d1e8e7fe6be5a1f257f0eb32 + md5: 8397539e3a0bbd1695584fb4f927485a depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 constrains: - jpeg <0.0.0a license: IJG AND BSD-3-Clause AND Zlib purls: [] - size: 628947 - timestamp: 1745268527144 -- conda: https://prefix.dev/conda-forge/osx-arm64/libjpeg-turbo-3.1.0-h5505292_0.conda - sha256: 78df2574fa6aa5b6f5fc367c03192f8ddf8e27dc23641468d54e031ff560b9d4 - md5: 01caa4fbcaf0e6b08b3aef1151e91745 + size: 633710 + timestamp: 1762094827865 +- conda: https://prefix.dev/conda-forge/osx-arm64/libjpeg-turbo-3.1.2-hc919400_0.conda + sha256: 6c061c56058bb10374daaef50e81b39cf43e8aee21f0037022c0c39c4f31872f + md5: f0695fbecf1006f27f4395d64bd0c4b8 depends: - __osx >=11.0 constrains: - jpeg <0.0.0a license: IJG AND BSD-3-Clause AND Zlib purls: [] - size: 553624 - timestamp: 1745268405713 -- conda: https://prefix.dev/conda-forge/linux-64/liblapack-3.9.0-35_h7ac8fdf_openblas.conda - build_number: 35 - sha256: 3967e62d4d1d5c1492f861864afca95aaa8cac14e696ce7b9be7d0b6a50507e8 - md5: 88fa5489509c1da59ab2ee6b234511a5 + size: 551197 + timestamp: 1762095054358 +- conda: https://prefix.dev/conda-forge/linux-64/liblapack-3.11.0-1_h47877c9_openblas.conda + build_number: 1 + sha256: b87938dc1220984c4313045d97422723f96ba4639676639a95ba144e2359f875 + md5: dee12a83aa4aca5077ea23c0605de044 depends: - - libblas 3.9.0 35_h59b9bed_openblas + - libblas 3.11.0 1_h4a7cf45_openblas constrains: - - blas 2.135 openblas - - libcblas 3.9.0 35*_openblas - - liblapacke 3.9.0 35*_openblas + - libcblas 3.11.0 1*_openblas + - blas 2.301 openblas + - liblapacke 3.11.0 1*_openblas license: BSD-3-Clause license_family: BSD purls: [] - size: 16920 - timestamp: 1757002835750 -- conda: https://prefix.dev/conda-forge/osx-arm64/liblapack-3.9.0-37_hd9741b5_openblas.conda - build_number: 37 - sha256: 61a3f8928431f74c359669ea68b5abedbbd46efb06f15de1e5c7e5d40f545263 - md5: 53335fc42466f597d0bc6d66a9ed4468 + size: 18486 + timestamp: 1763447033135 +- conda: https://prefix.dev/conda-forge/osx-arm64/liblapack-3.11.0-1_hd9741b5_openblas.conda + build_number: 1 + sha256: acee73900f85c8cf2db56540e905c8ac32e08bccc08d8b54bf4091b5a9ad1ed9 + md5: 5659bf8243896cb24e3de819d422b1a3 depends: - - libblas 3.9.0 37_h51639a9_openblas + - libblas 3.11.0 1_h51639a9_openblas constrains: - - liblapacke 3.9.0 37*_openblas - - blas 2.137 openblas - - libcblas 3.9.0 37*_openblas + - blas 2.301 openblas + - liblapacke 3.11.0 1*_openblas + - libcblas 3.11.0 1*_openblas license: BSD-3-Clause license_family: BSD purls: [] - size: 17633 - timestamp: 1760213604248 + size: 18703 + timestamp: 1763447928749 - conda: https://prefix.dev/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 md5: 1a580f7796c7bf6393fddb8bbbde58dc @@ -3088,9 +3001,9 @@ packages: purls: [] size: 216719 timestamp: 1745826006052 -- conda: https://prefix.dev/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_2.conda - sha256: 1b51d1f96e751dc945cc06f79caa91833b0c3326efe24e9b506bd64ef49fc9b0 - md5: dfc5aae7b043d9f56ba99514d5e60625 +- conda: https://prefix.dev/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda + sha256: 199d79c237afb0d4780ccd2fbf829cea80743df60df4705202558675e07dd2c5 + md5: be43915efc66345cccb3c310b6ed0374 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -3101,11 +3014,11 @@ packages: license: BSD-3-Clause license_family: BSD purls: [] - size: 5938936 - timestamp: 1755474342204 -- conda: https://prefix.dev/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_ha158390_2.conda - sha256: ddd201896c3f2d9d1911e8fb1aa34bf876795376f0fa5779c79b8998692f6800 - md5: e9f522513b5bbc6381f124f46e78fe36 + size: 5927939 + timestamp: 1763114673331 +- conda: https://prefix.dev/conda-forge/osx-arm64/libopenblas-0.3.30-openmp_ha158390_3.conda + sha256: dcc626c7103503d1dfc0371687ad553cb948b8ed0249c2a721147bdeb8db4a73 + md5: a18a7f471c517062ee71b843ef95eb8a depends: - __osx >=11.0 - libgfortran @@ -3116,8 +3029,8 @@ packages: license: BSD-3-Clause license_family: BSD purls: [] - size: 4284271 - timestamp: 1760594266347 + size: 4285762 + timestamp: 1761749506256 - conda: https://prefix.dev/conda-forge/linux-64/libopus-1.5.2-hd0c01bc_0.conda sha256: 786d43678d6d1dc5f88a6bad2d02830cfd5a0184e84a8caa45694049f0e3ea5f md5: b64523fb87ac6f87f0790f324ad43046 @@ -3194,26 +3107,23 @@ packages: purls: [] size: 2281852 timestamp: 1668470370774 -- conda: https://prefix.dev/conda-forge/linux-64/librsvg-2.58.4-he92a37e_3.conda - sha256: a45ef03e6e700cc6ac6c375e27904531cf8ade27eb3857e080537ff283fb0507 - md5: d27665b20bc4d074b86e628b3ba5ab8b +- conda: https://prefix.dev/conda-forge/linux-64/librsvg-2.60.0-h61e6d4b_0.conda + sha256: 960b137673b2b8293e2a12d194add72967b3bf12fcdf691e7ad8bd5c8318cec3 + md5: 91e6d4d684e237fba31b9815c4b40edf depends: - __glibc >=2.17,<3.0.a0 - cairo >=1.18.4,<2.0a0 - - freetype >=2.13.3,<3.0a0 - - gdk-pixbuf >=2.42.12,<3.0a0 - - harfbuzz >=11.0.0,<12.0a0 - - libgcc >=13 - - libglib >=2.84.0,<3.0a0 - - libpng >=1.6.47,<1.7.0a0 - - libxml2 >=2.13.7,<2.14.0a0 - - pango >=1.56.3,<2.0a0 + - gdk-pixbuf >=2.44.3,<3.0a0 + - libgcc >=14 + - libglib >=2.86.0,<3.0a0 + - libxml2-16 >=2.14.6 + - pango >=1.56.4,<2.0a0 constrains: - __glibc >=2.17 license: LGPL-2.1-or-later purls: [] - size: 6543651 - timestamp: 1743368725313 + size: 3421977 + timestamp: 1759327942156 - conda: https://prefix.dev/conda-forge/osx-arm64/librsvg-2.60.0-h5c55ec3_0.conda sha256: ca5a2de5d3f68e8d6443ea1bf193c1596a278e6f86018017c0ccd4928eaf8971 md5: 05ad1d6b6fb3b384f7a07128025725cb @@ -3263,28 +3173,29 @@ packages: purls: [] size: 317185 timestamp: 1695747981394 -- conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda - sha256: 6d9c32fc369af5a84875725f7ddfbfc2ace795c28f246dc70055a79f9b2003da - md5: 0b367fad34931cb79e0d6b7e5c06bb1c +- conda: https://prefix.dev/conda-forge/linux-64/libsqlite-3.51.0-hee844dc_0.conda + sha256: 4c992dcd0e34b68f843e75406f7f303b1b97c248d18f3c7c330bdc0bc26ae0b3 + md5: 729a572a3ebb8c43933b30edcc628ceb depends: - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 - libgcc >=14 - libzlib >=1.3.1,<2.0a0 license: blessing purls: [] - size: 932581 - timestamp: 1753948484112 -- conda: https://prefix.dev/conda-forge/osx-arm64/libsqlite-3.50.4-h4237e3c_0.conda - sha256: 802ebe62e6bc59fc26b26276b793e0542cfff2d03c086440aeaf72fb8bbcec44 - md5: 1dcb0468f5146e38fae99aef9656034b + size: 945576 + timestamp: 1762299687230 +- conda: https://prefix.dev/conda-forge/osx-arm64/libsqlite-3.51.0-h8adb53f_0.conda + sha256: b43d198f147f46866e5336c4a6b91668beef698bfba69d1706158460eadb2c1b + md5: 5fb1945dbc6380e6fe7e939a62267772 depends: - __osx >=11.0 - icu >=75.1,<76.0a0 - libzlib >=1.3.1,<2.0a0 license: blessing purls: [] - size: 902645 - timestamp: 1753948599139 + size: 909508 + timestamp: 1762300078624 - conda: https://prefix.dev/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 md5: eecce068c7e4eddeb169591baac20ac4 @@ -3309,49 +3220,47 @@ packages: purls: [] size: 279193 timestamp: 1745608793272 -- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda - sha256: 0f5f61cab229b6043541c13538d75ce11bd96fb2db76f94ecf81997b1fde6408 - md5: 4e02a49aaa9d5190cb630fa43528fbe6 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-15.2.0-h8f9b012_7.conda + sha256: 1b981647d9775e1cdeb2fab0a4dd9cd75a6b0de2963f6c3953dbd712f78334b3 + md5: 5b767048b1b3ee9a954b06f4084f93dc depends: - __glibc >=2.17,<3.0.a0 - - libgcc 15.1.0 h767d61c_5 + - libgcc 15.2.0 h767d61c_7 + constrains: + - libstdcxx-ng ==15.2.0=*_7 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 3896432 - timestamp: 1757042571458 -- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda - sha256: 7b8cabbf0ab4fe3581ca28fe8ca319f964078578a51dd2ca3f703c1d21ba23ff - md5: 8bba50c7f4679f08c861b597ad2bda6b + size: 3898269 + timestamp: 1759968103436 +- conda: https://prefix.dev/conda-forge/linux-64/libstdcxx-ng-15.2.0-h4852527_7.conda + sha256: 024fd46ac3ea8032a5ec3ea7b91c4c235701a8bf0e6520fe5e6539992a6bd05f + md5: f627678cf829bd70bccf141a19c3ad3e depends: - - libstdcxx 15.1.0 h8f9b012_5 + - libstdcxx 15.2.0 h8f9b012_7 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL purls: [] - size: 29233 - timestamp: 1757042603319 -- conda: https://prefix.dev/conda-forge/linux-64/libsystemd0-257.7-h4e0b6ca_0.conda - sha256: e26b22c0ae40fb6ad4356104d5fa4ec33fe8dd8a10e6aef36a9ab0c6a6f47275 - md5: 1e12c8aa74fa4c3166a9bdc135bc4abf + size: 29343 + timestamp: 1759968157195 +- conda: https://prefix.dev/conda-forge/linux-64/libsystemd0-257.10-hd0affe5_2.conda + sha256: b30c06f60f03c2cf101afeb3452f48f12a2553b4cb631c9460c8a8ccf0813ae5 + md5: b04e0a2163a72588a40cde1afd6f2d18 depends: - __glibc >=2.17,<3.0.a0 - - libcap >=2.75,<2.76.0a0 - - libgcc >=13 - - libgcrypt-lib >=1.11.1,<2.0a0 - - liblzma >=5.8.1,<6.0a0 - - lz4-c >=1.10.0,<1.11.0a0 - - zstd >=1.5.7,<1.6.0a0 + - libcap >=2.77,<2.78.0a0 + - libgcc >=14 license: LGPL-2.1-or-later purls: [] - size: 487969 - timestamp: 1750949895969 -- conda: https://prefix.dev/conda-forge/linux-64/libtiff-4.7.0-h8261f1e_6.conda - sha256: c62694cd117548d810d2803da6d9063f78b1ffbf7367432c5388ce89474e9ebe - md5: b6093922931b535a7ba566b6f384fbe6 + size: 491211 + timestamp: 1763011323224 +- conda: https://prefix.dev/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda + sha256: e5f8c38625aa6d567809733ae04bb71c161a42e44a9fa8227abe61fa5c60ebe0 + md5: cd5a90476766d53e901500df9215e927 depends: - __glibc >=2.17,<3.0.a0 - lerc >=4.0.0,<5.0a0 - - libdeflate >=1.24,<1.25.0a0 + - libdeflate >=1.25,<1.26.0a0 - libgcc >=14 - libjpeg-turbo >=3.1.0,<4.0a0 - liblzma >=5.8.1,<6.0a0 @@ -3361,16 +3270,16 @@ packages: - zstd >=1.5.7,<1.6.0a0 license: HPND purls: [] - size: 433078 - timestamp: 1755011934951 -- conda: https://prefix.dev/conda-forge/osx-arm64/libtiff-4.7.1-h7dc4979_0.conda - sha256: 6bc1b601f0d3ee853acd23884a007ac0a0290f3609dabb05a47fc5a0295e2b53 - md5: 2bb9e04e2da869125e2dc334d665f00d + size: 435273 + timestamp: 1762022005702 +- conda: https://prefix.dev/conda-forge/osx-arm64/libtiff-4.7.1-h4030677_1.conda + sha256: e9248077b3fa63db94caca42c8dbc6949c6f32f94d1cafad127f9005d9b1507f + md5: e2a72ab2fa54ecb6abab2b26cde93500 depends: - __osx >=11.0 - lerc >=4.0.0,<5.0a0 - libcxx >=19 - - libdeflate >=1.24,<1.25.0a0 + - libdeflate >=1.25,<1.26.0a0 - libjpeg-turbo >=3.1.0,<4.0a0 - liblzma >=5.8.1,<6.0a0 - libwebp-base >=1.6.0,<2.0a0 @@ -3378,19 +3287,19 @@ packages: - zstd >=1.5.7,<1.6.0a0 license: HPND purls: [] - size: 373640 - timestamp: 1758278641520 -- conda: https://prefix.dev/conda-forge/linux-64/libudev1-257.7-hbe16f8c_0.conda - sha256: 3fca2655f4cf2ce6b618a2b52e3dce92f27f429732b88080567d5bbeea404c82 - md5: 5a23e52bd654a5297bd3e247eebab5a3 + size: 373892 + timestamp: 1762022345545 +- conda: https://prefix.dev/conda-forge/linux-64/libudev1-257.10-hd0affe5_2.conda + sha256: 751cf346f0f56cc9bfa43f7b5c9c30df2fcec8d84d164ac0cd74a27a3af79f30 + md5: 2f6b30acaa0d6e231d01166549108e2c depends: - __glibc >=2.17,<3.0.a0 - - libcap >=2.75,<2.76.0a0 - - libgcc >=13 + - libcap >=2.77,<2.78.0a0 + - libgcc >=14 license: LGPL-2.1-or-later purls: [] - size: 143533 - timestamp: 1750949902296 + size: 144395 + timestamp: 1763011330153 - conda: https://prefix.dev/conda-forge/linux-64/libunwind-1.8.3-h65a8314_0.conda sha256: 71c8b9d5c72473752a0bb6e91b01dd209a03916cb71f36cc6a564e3a2a132d7a md5: e179a69edd30d75c0144d7a380b88f28 @@ -3435,16 +3344,17 @@ packages: purls: [] size: 83849 timestamp: 1748856224950 -- conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.41.1-he9a06e4_0.conda - sha256: 776e28735cee84b97e4d05dd5d67b95221a3e2c09b8b13e3d6dbe6494337d527 - md5: af930c65e9a79a3423d6d36e265cef65 +- conda: https://prefix.dev/conda-forge/linux-64/libuuid-2.41.2-he9a06e4_0.conda + sha256: e5ec6d2ad7eef538ddcb9ea62ad4346fde70a4736342c4ad87bd713641eb9808 + md5: 80c07c68d2f6870250959dcc95b209d1 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: BSD-3-Clause + license_family: BSD purls: [] - size: 37087 - timestamp: 1757334557450 + size: 37135 + timestamp: 1758626800002 - conda: https://prefix.dev/conda-forge/linux-64/libuv-1.51.0-hb03c661_1.conda sha256: c180f4124a889ac343fc59d15558e93667d894a966ec6fdb61da1604481be26b md5: 0f03292cc56bf91a077a134ea8747118 @@ -3494,6 +3404,22 @@ packages: purls: [] size: 259122 timestamp: 1753879389702 +- conda: https://prefix.dev/conda-forge/linux-64/libvulkan-loader-1.4.328.1-h5279c79_0.conda + sha256: bbabc5c48b63ff03f440940a11d4648296f5af81bb7630d98485405cd32ac1ce + md5: 372a62464d47d9e966b630ffae3abe73 + depends: + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libgcc >=14 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxrandr >=1.5.4,<2.0a0 + constrains: + - libvulkan-headers 1.4.328.1.* + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 197672 + timestamp: 1759972155030 - conda: https://prefix.dev/conda-forge/osx-arm64/libvulkan-loader-1.4.328.1-h49c215f_0.conda sha256: 7cdf4f61f38dad4765762d1e8f916c81e8221414911012f8aba294f5dce0e0ba md5: 978586f8c141eed794868a8f9834e3b0 @@ -3555,25 +3481,42 @@ packages: purls: [] size: 100393 timestamp: 1702724383534 -- conda: https://prefix.dev/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda - sha256: 23f47e86cc1386e7f815fa9662ccedae151471862e971ea511c5c886aa723a54 - md5: 74e91c36d0eef3557915c68b6c2bef96 +- conda: https://prefix.dev/conda-forge/linux-64/libxkbcommon-1.13.0-hca5e8e5_0.conda + sha256: 576ce5378cc6a2b722ff33d2359ccb74dea1e6465daa45116e57550f1eb4ba7e + md5: aa65b4add9574bb1d23c76560c5efd4c depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 - libstdcxx >=14 - libxcb >=1.17.0,<2.0a0 - - libxml2 >=2.13.8,<2.14.0a0 + - libxml2 + - libxml2-16 >=2.14.6 - xkeyboard-config - xorg-libxau >=1.0.12,<2.0a0 license: MIT/X11 Derivative license_family: MIT purls: [] - size: 791328 - timestamp: 1754703902365 -- conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda - sha256: 03deb1ec6edfafc5aaeecadfc445ee436fecffcda11fcd97fde9b6632acb583f - md5: 10bcbd05e1c1c9d652fccb42b776a9fa + size: 843995 + timestamp: 1762341607312 +- conda: https://prefix.dev/conda-forge/linux-64/libxml2-2.15.1-h26afc86_0.conda + sha256: ec0735ae56c3549149eebd7dc22c0bed91fd50c02eaa77ff418613ddda190aa8 + md5: e512be7dc1f84966d50959e900ca121f + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.1,<6.0a0 + - libxml2-16 2.15.1 ha9997c6_0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 45283 + timestamp: 1761015644057 +- conda: https://prefix.dev/conda-forge/linux-64/libxml2-16-2.15.1-ha9997c6_0.conda + sha256: 71436e72a286ef8b57d6f4287626ff91991eb03c7bdbe835280521791efd1434 + md5: e7733bc6785ec009e47a224a71917e84 depends: - __glibc >=2.17,<3.0.a0 - icu >=75.1,<76.0a0 @@ -3581,11 +3524,13 @@ packages: - libiconv >=1.18,<2.0a0 - liblzma >=5.8.1,<6.0a0 - libzlib >=1.3.1,<2.0a0 + constrains: + - libxml2 2.15.1 license: MIT license_family: MIT purls: [] - size: 698448 - timestamp: 1754315344761 + size: 556302 + timestamp: 1761015637262 - conda: https://prefix.dev/conda-forge/osx-arm64/libxml2-16-2.15.1-h0ff4647_0.conda sha256: ebe2dd9da94280ad43da936efa7127d329b559f510670772debc87602b49b06d md5: 438c97d1e9648dd7342f86049dd44638 @@ -3627,30 +3572,19 @@ packages: purls: [] size: 46438 timestamp: 1727963202283 -- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-openmp-21.1.4-h4a912ad_0.conda - sha256: 3f977e96f4c87d00c2f37e74609ac1f897a27d7a31d49078afe415f1d7c063bf - md5: 8e3ed09e85fd3f3ff3496b2a04f88e21 +- conda: https://prefix.dev/conda-forge/osx-arm64/llvm-openmp-21.1.6-h4a912ad_0.conda + sha256: 51ebeacae9225649e2c3bbfc9ed2ed690400b78ba79d0d3ee9ff428e8b951fed + md5: 4a274d80967416bce3c7d89bf43923ec depends: - __osx >=11.0 constrains: - - openmp 21.1.4|21.1.4.* + - openmp 21.1.6|21.1.6.* - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception + license_family: APACHE purls: [] - size: 286030 - timestamp: 1761131615697 -- conda: https://prefix.dev/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda - sha256: 47326f811392a5fd3055f0f773036c392d26fdb32e4d8e7a8197eed951489346 - md5: 9de5350a85c4a20c685259b889aa6393 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libstdcxx >=13 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 167055 - timestamp: 1733741040117 + size: 286206 + timestamp: 1763529774822 - conda: https://prefix.dev/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda sha256: 7b1da4b5c40385791dbc3cc85ceea9fad5da680a27d5d3cb8bfaa185e304a89e md5: 5b5203189eb668f042ac2b0826244964 @@ -3660,7 +3594,7 @@ packages: license: MIT license_family: MIT purls: - - pkg:pypi/markdown-it-py?source=compressed-mapping + - pkg:pypi/markdown-it-py?source=hash-mapping size: 64736 timestamp: 1754951288511 - conda: https://prefix.dev/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda @@ -3789,9 +3723,9 @@ packages: - pkg:pypi/numpy?source=hash-mapping size: 6893464 timestamp: 1732314808608 -- conda: https://prefix.dev/conda-forge/linux-64/openssl-3.5.2-h26f9b46_0.conda - sha256: c9f54d4e8212f313be7b02eb962d0cb13a8dae015683a403d3accd4add3e520e - md5: ffffb341206dd0dab0c36053c048d621 +- conda: https://prefix.dev/conda-forge/linux-64/openssl-3.6.0-h26f9b46_0.conda + sha256: a47271202f4518a484956968335b2521409c8173e123ab381e775c358c67fe6d + md5: 9ee58d5c534af06558933af3c845a780 depends: - __glibc >=2.17,<3.0.a0 - ca-certificates @@ -3799,19 +3733,19 @@ packages: license: Apache-2.0 license_family: Apache purls: [] - size: 3128847 - timestamp: 1754465526100 -- conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.5.4-h5503f6c_0.conda - sha256: f0512629f9589392c2fb9733d11e753d0eab8fc7602f96e4d7f3bd95c783eb07 - md5: 71118318f37f717eefe55841adb172fd + size: 3165399 + timestamp: 1762839186699 +- conda: https://prefix.dev/conda-forge/osx-arm64/openssl-3.6.0-h5503f6c_0.conda + sha256: ebe93dafcc09e099782fe3907485d4e1671296bc14f8c383cb6f3dfebb773988 + md5: b34dc4172653c13dcf453862f251af2b depends: - __osx >=11.0 - ca-certificates license: Apache-2.0 license_family: Apache purls: [] - size: 3067808 - timestamp: 1759324763146 + size: 3108371 + timestamp: 1762839712322 - conda: https://prefix.dev/conda-forge/linux-64/opusfile-0.12-h3358134_2.conda sha256: f4df9df880e405e5c856383f869d5b9d434f78fb7c234c9e7b099ab604fb7fc3 md5: 5931bcae00b98f952696b6bcdd0be34b @@ -3961,18 +3895,6 @@ packages: purls: [] size: 248045 timestamp: 1754665282033 -- conda: https://prefix.dev/conda-forge/noarch/platformdirs-4.4.0-pyhcf101f3_0.conda - sha256: dfe0fa6e351d2b0cef95ac1a1533d4f960d3992f9e0f82aeb5ec3623a699896b - md5: cc9d9a3929503785403dbfad9f707145 - depends: - - python >=3.10 - - python - license: MIT - license_family: MIT - purls: - - pkg:pypi/platformdirs?source=compressed-mapping - size: 23653 - timestamp: 1756227402815 - conda: https://prefix.dev/conda-forge/noarch/platformdirs-4.5.0-pyhcf101f3_0.conda sha256: 7efd51b48d908de2d75cbb3c4a2e80dd9454e1c5bb8191b261af3136f7fa5888 md5: 5c7a868f8241e64e1cf5fdf4962f23e2 @@ -4018,46 +3940,46 @@ packages: purls: [] size: 78863 timestamp: 1693868663440 -- conda: https://prefix.dev/conda-forge/linux-64/portmidi-2.0.6-hf4617a5_0.conda - sha256: 4b16598ded9fd0636ace2e9f6c31835ccbeaccc3ae284457c9aea9d810f558db - md5: 4461787d1087ad942cc2ea151fd422c3 +- conda: https://prefix.dev/conda-forge/linux-64/portmidi-2.0.7-h3cb78e3_0.conda + sha256: 7139889de1da0e5990c9baface279c62c6be71bfb650897ecc92b9fa84aaa482 + md5: 378b689c31af1260dbf6e5e5eb02166c depends: - __glibc >=2.17,<3.0.a0 - alsa-lib >=1.2.14,<1.3.0a0 - - libgcc >=13 - - libstdcxx >=13 + - libgcc >=14 + - libstdcxx >=14 license: MIT license_family: MIT purls: [] - size: 43976 - timestamp: 1750372118122 -- conda: https://prefix.dev/conda-forge/osx-arm64/portmidi-2.0.6-h286801f_0.conda - sha256: adddc071e03a799d5e18d6f1fa0f0d6fc9a99b3f7a6796b18a12a7b5e3f05885 - md5: 5985a83d15a126fe0c9c6abf7ff3d1df + size: 44047 + timestamp: 1761471639423 +- conda: https://prefix.dev/conda-forge/osx-arm64/portmidi-2.0.7-haf25636_0.conda + sha256: d74c61e5de5d6a67484b22fc2d005c97668e400626be07e576580cf461b3c9d9 + md5: effa51f505671206ba4b86acce7946ff depends: - __osx >=11.0 - - libcxx >=18 + - libcxx >=19 license: MIT license_family: MIT purls: [] - size: 41407 - timestamp: 1750372262579 -- conda: https://prefix.dev/conda-forge/noarch/pre-commit-4.3.0-pyha770c72_0.conda - sha256: 66b6d429ab2201abaa7282af06b17f7631dcaafbc5aff112922b48544514b80a - md5: bc6c44af2a9e6067dd7e949ef10cdfba + size: 41359 + timestamp: 1761471916499 +- conda: https://prefix.dev/conda-forge/noarch/pre-commit-4.4.0-pyha770c72_0.conda + sha256: 5eee94ab06bb74ad164862d15c18e932493c5b959928e7889b91dee73f550152 + md5: c130573bb7a166e93d5bd01c94ae38e1 depends: - cfgv >=2.0.0 - identify >=1.0.0 - nodeenv >=0.11.1 - - python >=3.9 + - python >=3.10 - pyyaml >=5.1 - virtualenv >=20.10.0 license: MIT license_family: MIT purls: - pkg:pypi/pre-commit?source=hash-mapping - size: 195839 - timestamp: 1754831350570 + size: 200293 + timestamp: 1762692428418 - conda: https://prefix.dev/conda-forge/linux-64/protobuf-3.20.2-py311ha362b79_1.conda sha256: b5927c5e5d3d2bee29e87cfee3e45781e6f6fd663e890389726cd513ef746177 md5: 9d64275197aab7121cd9318b593a21bd @@ -4125,36 +4047,30 @@ packages: - pkg:pypi/ptyprocess?source=hash-mapping size: 19457 timestamp: 1733302371990 -- conda: https://prefix.dev/conda-forge/linux-64/pulseaudio-client-17.0-hac146a9_1.conda - sha256: d2377bb571932f2373f593b7b2fc3b9728dc6ae5b993b1b65d7f2c8bb39a0b49 - md5: 66b1fa9608d8836e25f9919159adc9c6 +- conda: https://prefix.dev/conda-forge/linux-64/pulseaudio-client-17.0-h9a6aba3_3.conda + sha256: 0a0858c59805d627d02bdceee965dd84fde0aceab03a2f984325eec08d822096 + md5: b8ea447fdf62e3597cb8d2fae4eb1a90 depends: - __glibc >=2.17,<3.0.a0 - - dbus >=1.13.6,<2.0a0 - - libgcc >=13 - - libglib >=2.82.2,<3.0a0 + - dbus >=1.16.2,<2.0a0 + - libgcc >=14 + - libglib >=2.86.1,<3.0a0 - libiconv >=1.18,<2.0a0 - libsndfile >=1.2.2,<1.3.0a0 - - libsystemd0 >=257.4 + - libsystemd0 >=257.10 - libxcb >=1.17.0,<2.0a0 constrains: - - pulseaudio 17.0 *_1 + - pulseaudio 17.0 *_3 license: LGPL-2.1-or-later license_family: LGPL purls: [] - size: 764231 - timestamp: 1742507189208 -- pypi: https://files.pythonhosted.org/packages/f6/f0/10642828a8dfb741e5f3fbaac830550a518a775c7fff6f04a007259b0548/py-1.11.0-py2.py3-none-any.whl - name: py - version: 1.11.0 - sha256: 607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- pypi: https://files.pythonhosted.org/packages/39/1c/9f32299572bce7c1d46ca98425d82f3fe6723a526f05a01b39d491cbfdf6/py_trees-2.3.0-py3-none-any.whl + size: 750785 + timestamp: 1763148198088 +- pypi: https://files.pythonhosted.org/packages/7d/0a/2e0c30342586dabb0b4b7946393a7aeb725fca7b4549fb02e128a1a0fe87/py_trees-2.4.0-py3-none-any.whl name: py-trees - version: 2.3.0 - sha256: 02831face639b15edd5830df76dd59f358358177384543cf17a5e019370bffc2 + version: 2.4.0 + sha256: c26a2d23f70871ce093abd5f8425998529bfe7b97cc563316e9c3c9cec20c312 requires_dist: - - py>=1.11.0,<2.0.0 - pydot>=1.4 requires_python: '>=3.9,<4.0' - conda: https://prefix.dev/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda @@ -4249,18 +4165,10 @@ packages: - pkg:pypi/pygments?source=hash-mapping size: 889287 timestamp: 1750615908735 -- pypi: https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl - name: pyparsing - version: 3.2.3 - sha256: a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf - requires_dist: - - railroad-diagrams ; extra == 'diagrams' - - jinja2 ; extra == 'diagrams' - requires_python: '>=3.9' -- pypi: https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl +- pypi: https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl name: pyparsing - version: 3.2.5 - sha256: e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e + version: 3.3.2 + sha256: 850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d requires_dist: - railroad-diagrams ; extra == 'diagrams' - jinja2 ; extra == 'diagrams' @@ -4295,24 +4203,25 @@ packages: - pkg:pypi/pytest?source=hash-mapping size: 259195 timestamp: 1733217599806 -- conda: https://prefix.dev/conda-forge/linux-64/python-3.10.18-hd6af730_0_cpython.conda - sha256: 4111e5504fa4f4fb431d3a73fa606daccaf23a5a1da0f17a30db70ffad9336a7 - md5: 4ea0c77cdcb0b81813a0436b162d7316 +- conda: https://prefix.dev/conda-forge/linux-64/python-3.10.19-h3c07f61_2_cpython.conda + build_number: 2 + sha256: 6e3b6b69b3cacfc7610155d58407a003820eaacd50fbe039abff52b5e70b1e9b + md5: 27ac896a8b4970f8977503a9e70dc745 depends: - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.7.0,<3.0a0 + - libexpat >=2.7.1,<3.0a0 - libffi >=3.4,<4.0a0 - - libgcc >=13 + - libgcc >=14 - liblzma >=5.8.1,<6.0a0 - libnsl >=2.0.1,<2.1.0a0 - - libsqlite >=3.50.0,<4.0a0 - - libuuid >=2.38.1,<3.0a0 + - libsqlite >=3.50.4,<4.0a0 + - libuuid >=2.41.2,<3.0a0 - libxcrypt >=4.4.36 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.5.0,<4.0a0 + - openssl >=3.5.4,<4.0a0 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata @@ -4320,26 +4229,27 @@ packages: - python_abi 3.10.* *_cp310 license: Python-2.0 purls: [] - size: 25042108 - timestamp: 1749049293621 -- conda: https://prefix.dev/conda-forge/linux-64/python-3.11.13-h9e4cc4f_0_cpython.conda - sha256: 9979a7d4621049388892489267139f1aa629b10c26601ba5dce96afc2b1551d4 - md5: 8c399445b6dc73eab839659e6c7b5ad1 + size: 25311690 + timestamp: 1761173015969 +- conda: https://prefix.dev/conda-forge/linux-64/python-3.11.14-hd63d673_2_cpython.conda + build_number: 2 + sha256: 5b872f7747891e50e990a96d2b235236a5c66cc9f8c9dcb7149aee674ea8145a + md5: c4202a55b4486314fbb8c11bc43a29a0 depends: - __glibc >=2.17,<3.0.a0 - bzip2 >=1.0.8,<2.0a0 - ld_impl_linux-64 >=2.36.1 - - libexpat >=2.7.0,<3.0a0 - - libffi >=3.4.6,<3.5.0a0 - - libgcc >=13 + - libexpat >=2.7.1,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 - liblzma >=5.8.1,<6.0a0 - libnsl >=2.0.1,<2.1.0a0 - - libsqlite >=3.50.0,<4.0a0 - - libuuid >=2.38.1,<3.0a0 + - libsqlite >=3.50.4,<4.0a0 + - libuuid >=2.41.2,<3.0a0 - libxcrypt >=4.4.36 - libzlib >=1.3.1,<2.0a0 - ncurses >=6.5,<7.0a0 - - openssl >=3.5.0,<4.0a0 + - openssl >=3.5.4,<4.0a0 - readline >=8.2,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata @@ -4347,12 +4257,12 @@ packages: - python_abi 3.11.* *_cp311 license: Python-2.0 purls: [] - size: 30629559 - timestamp: 1749050021812 -- conda: https://prefix.dev/conda-forge/osx-arm64/python-3.10.19-h14e4db3_1_cpython.conda - build_number: 1 - sha256: 8c32dc294a9da5c9668420c97a73c2de55816d048ceb8e811a3fc621a4f89029 - md5: d4ec41a8af667ebce8da378668cb5a2d + size: 30874708 + timestamp: 1761174520369 +- conda: https://prefix.dev/conda-forge/osx-arm64/python-3.10.19-hcd7f573_2_cpython.conda + build_number: 2 + sha256: 7bac6cc075d1d7897f06fa14c1bc87eb16b9524c6002e0c72b0ed3326af51695 + md5: feb559b139819a7326f992711cb50872 depends: - __osx >=11.0 - bzip2 >=1.0.8,<2.0a0 @@ -4370,17 +4280,17 @@ packages: - python_abi 3.10.* *_cp310 license: Python-2.0 purls: [] - size: 12453543 - timestamp: 1760366963622 -- conda: https://prefix.dev/conda-forge/osx-arm64/python-3.11.14-hec0b533_1_cpython.conda - build_number: 1 - sha256: f1fc90c0929f744d0db11d1247cd97632134494cea2a99fa24996ad928e904a8 - md5: 64d46fd57bf5b2793f75fceb6f3b6189 + size: 11674631 + timestamp: 1761173465015 +- conda: https://prefix.dev/conda-forge/osx-arm64/python-3.11.14-h18782d2_2_cpython.conda + build_number: 2 + sha256: 64a2bc6be8582fae75f1f2da7bdc49afd81c2793f65bb843fc37f53c99734063 + md5: da948e6cd735249ab4cfbb3fdede785e depends: - __osx >=11.0 - bzip2 >=1.0.8,<2.0a0 - libexpat >=2.7.1,<3.0a0 - - libffi >=3.4.6,<3.5.0a0 + - libffi >=3.5.2,<3.6.0a0 - liblzma >=5.8.1,<6.0a0 - libsqlite >=3.50.4,<4.0a0 - libzlib >=1.3.1,<2.0a0 @@ -4393,8 +4303,8 @@ packages: - python_abi 3.11.* *_cp311 license: Python-2.0 purls: [] - size: 14794480 - timestamp: 1760366123572 + size: 14788204 + timestamp: 1761174033541 - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.10-8_cp310.conda build_number: 8 sha256: 7ad76fa396e4bde336872350124c0819032a9e8a0a40590744ff9527b54351c1 @@ -4417,12 +4327,12 @@ packages: purls: [] size: 7003 timestamp: 1752805919375 -- conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.2-py311h2dc5d0c_2.conda - sha256: d107ad62ed5c62764fba9400f2c423d89adf917d687c7f2e56c3bfed605fb5b3 - md5: 014417753f948da1f70d132b2de573be +- conda: https://prefix.dev/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_0.conda + sha256: 7dc5c27c0c23474a879ef5898ed80095d26de7f89f4720855603c324cca19355 + md5: 707c3d23f2476d3bfde8345b4e7d7853 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 - python >=3.11,<3.12.0a0 - python_abi 3.11.* *_cp311 - yaml >=0.2.5,<0.3.0a0 @@ -4430,8 +4340,8 @@ packages: license_family: MIT purls: - pkg:pypi/pyyaml?source=hash-mapping - size: 213136 - timestamp: 1737454846598 + size: 211606 + timestamp: 1758892088237 - conda: https://prefix.dev/conda-forge/osx-arm64/pyyaml-6.0.3-py311ha9b3269_0.conda sha256: 747c1b94222481a727aeeb912407f862a93a1bb4e704be3a8236768182ac0290 md5: 109a9c326951cc9ab5df6a06cf5b930a @@ -4534,26 +4444,26 @@ packages: - pkg:pypi/rich?source=compressed-mapping size: 200840 timestamp: 1760026188268 -- conda: https://prefix.dev/conda-forge/linux-64/ruff-0.12.12-h718f522_0.conda +- conda: https://prefix.dev/conda-forge/linux-64/ruff-0.14.5-h813ae00_0.conda noarch: python - sha256: 76861e67f7b57303ec61b2a1569e83a972b253bd5c094ce40dcc4761a70e223f - md5: ae6fcbf2a0632943781a2421a1e30a7d + sha256: 3e425603d7ad058ba9ec21cc482328e5ccb776a458d3e92ee112f2f65631678a + md5: a4590632bd44d39c8f4f64a1c85ebe49 depends: - python - - libgcc >=14 - __glibc >=2.17,<3.0.a0 + - libgcc >=14 constrains: - __glibc >=2.17 license: MIT license_family: MIT purls: - - pkg:pypi/ruff?source=compressed-mapping - size: 10836594 - timestamp: 1757055819993 -- conda: https://prefix.dev/conda-forge/osx-arm64/ruff-0.14.1-h492a034_0.conda + - pkg:pypi/ruff?source=hash-mapping + size: 11098073 + timestamp: 1763078242921 +- conda: https://prefix.dev/conda-forge/osx-arm64/ruff-0.14.5-h382de68_0.conda noarch: python - sha256: 876780e215d7cbeea5b3ed090d0bc32d811e0c8b5b8d01a528d3864013307ecb - md5: cafec33d1bff4183d7c891860e8578d9 + sha256: c802549bba4a74e491c1f0c8d1dcf88b1adc151a39d698884734353cca1a4005 + md5: dfb6a5485cf34697a9245832f3f90c09 depends: - python - __osx >=11.0 @@ -4563,23 +4473,22 @@ packages: license_family: MIT purls: - pkg:pypi/ruff?source=compressed-mapping - size: 9937951 - timestamp: 1760644202217 -- conda: https://prefix.dev/conda-forge/linux-64/sdl2-2.32.54-h3f2d84a_0.conda - sha256: 7cd82ca1d1989de6ac28e72ba0bfaae1c055278f931b0c7ef51bb1abba3ddd2f - md5: 91f8537d64c4d52cbbb2910e8bd61bd2 + size: 10121479 + timestamp: 1763078323983 +- conda: https://prefix.dev/conda-forge/linux-64/sdl2-2.32.56-h54a6638_0.conda + sha256: 987ad072939fdd51c92ea8d3544b286bb240aefda329f9b03a51d9b7e777f9de + md5: cdd138897d94dc07d99afe7113a07bec depends: - - libgcc >=13 + - libstdcxx >=14 + - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libstdcxx >=13 - - libgcc >=13 - - sdl3 >=3.2.10,<4.0a0 - libgl >=1.7.0,<2.0a0 + - sdl3 >=3.2.22,<4.0a0 - libegl >=1.7.0,<2.0a0 license: Zlib purls: [] - size: 587053 - timestamp: 1745799881584 + size: 589145 + timestamp: 1757842881 - conda: https://prefix.dev/conda-forge/osx-arm64/sdl2-2.32.56-h248ca61_0.conda sha256: 704c5cae4bc839a18c70cbf3387d7789f1902828c79c6ddabcd34daf594f4103 md5: 092c5b693dc6adf5f409d12f33295a2a @@ -4660,78 +4569,79 @@ packages: purls: [] size: 188504 timestamp: 1695762176058 -- conda: https://prefix.dev/conda-forge/linux-64/sdl2_ttf-2.24.0-hc1d668e_1.conda - sha256: 5b72b99576455ba53cc294c8aa1ab389d6302a1072c90f76268257e70343fcfe - md5: 0385816e000e885b420cdcfc1b7de3a3 +- conda: https://prefix.dev/conda-forge/linux-64/sdl2_ttf-2.24.0-h287479f_0.conda + sha256: 431d19b666db6e7a4f09c37c43c83f115176a006b2ac321853ca26bee888c519 + md5: bccd5b74eb55a523dfcc66b857555714 depends: - __glibc >=2.17,<3.0.a0 - - freetype >=2.13.3,<3.0a0 - - harfbuzz >=11.0.0,<12.0a0 + - freetype >=2.12.1,<3.0a0 + - harfbuzz >=10.1.0 - libgcc >=13 - libzlib >=1.3.1,<2.0a0 - - sdl2 >=2.32.50,<3.0a0 + - sdl2 >=2.30.10,<3.0a0 license: Zlib purls: [] - size: 62419 - timestamp: 1743198496689 -- conda: https://prefix.dev/conda-forge/osx-arm64/sdl2_ttf-2.24.0-h49b19f9_1.conda - sha256: 8682907cc92eca66771e4fe951feb97396a1d76b73a6d910f3888d93951a3dc2 - md5: a9a40538ce016f25b160e80a193f4075 + size: 61954 + timestamp: 1736117956977 +- conda: https://prefix.dev/conda-forge/osx-arm64/sdl2_ttf-2.24.0-h443c5de_0.conda + sha256: 5dc56fd1de51dec2f7b63b1a9069ab35ab0494d9cd5af164ab0019cbd9564cf6 + md5: 3cf5cf83deccb663b4e932d3d4b28f57 depends: - __osx >=11.0 - - freetype >=2.13.3,<3.0a0 - - harfbuzz >=11.0.0,<12.0a0 - - sdl2 >=2.32.50,<3.0a0 + - freetype >=2.12.1,<3.0a0 + - harfbuzz >=10.1.0 + - sdl2 >=2.30.10,<3.0a0 license: Zlib purls: [] - size: 45515 - timestamp: 1743198654173 -- conda: https://prefix.dev/conda-forge/linux-64/sdl3-3.2.22-h68140b3_0.conda - sha256: 789ae811b7b93b01c2300461345027fd1a19a7a404e1b8729f58fbe81a82b3bc - md5: ebfddf2601e082193bb550924bbb9744 + size: 45429 + timestamp: 1736118165229 +- conda: https://prefix.dev/conda-forge/linux-64/sdl3-3.2.26-h68140b3_0.conda + sha256: 31bfb3db00feb74dab5c3420b6b7529cd9a044fda381c422adc817df09ae17b1 + md5: 8d9c193907f1c9defb46322f06990105 depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - libstdcxx >=14 - libgcc >=14 - - xorg-libxfixes >=6.0.1,<7.0a0 - - dbus >=1.16.2,<2.0a0 - - libegl >=1.7.0,<2.0a0 - - libudev1 >=257.7 - - libdrm >=2.4.125,<2.5.0a0 - - xorg-libx11 >=1.8.12,<2.0a0 - - xorg-libxcursor >=1.2.3,<2.0a0 - - libxkbcommon >=1.11.0,<2.0a0 + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - xorg-libxscrnsaver >=1.2.4,<2.0a0 + - libvulkan-loader >=1.4.328.1,<2.0a0 + - liburing >=2.12,<2.13.0a0 - libusb >=1.0.29,<2.0a0 + - libegl >=1.7.0,<2.0a0 + - libunwind >=1.8.3,<1.9.0a0 - libgl >=1.7.0,<2.0a0 + - dbus >=1.16.2,<2.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - libudev1 >=257.9 - pulseaudio-client >=17.0,<17.1.0a0 - - xorg-libxscrnsaver >=1.2.4,<2.0a0 - - libunwind >=1.8.2,<1.9.0a0 + - libxkbcommon >=1.12.3,<2.0a0 + - xorg-libxfixes >=6.0.2,<7.0a0 + - libdrm >=2.4.125,<2.5.0a0 - wayland >=1.24.0,<2.0a0 - - liburing >=2.12,<2.13.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 - xorg-libxext >=1.3.6,<2.0a0 license: Zlib purls: [] - size: 1936633 - timestamp: 1756780211365 -- conda: https://prefix.dev/conda-forge/osx-arm64/sdl3-3.2.24-h919df07_0.conda - sha256: 1533fa1a5614a4fa3419889de65a19a6d281a8b74e5c760c73376f7e84c4cf4e - md5: 9d88d4549fbb44074b5859c1571a8f5d + size: 1936312 + timestamp: 1761847993797 +- conda: https://prefix.dev/conda-forge/osx-arm64/sdl3-3.2.26-h919df07_0.conda + sha256: 18fb9c4c3f4d787151a38e493a8bfde329321700ae8530bda052aba315e7be99 + md5: ed708ea3309264c803198b22b706e1ed depends: - - __osx >=11.0 - libcxx >=19 + - __osx >=11.0 + - libvulkan-loader >=1.4.328.1,<2.0a0 - libusb >=1.0.29,<2.0a0 - dbus >=1.16.2,<2.0a0 - - libvulkan-loader >=1.4.313.0,<2.0a0 license: Zlib purls: [] - size: 1416326 - timestamp: 1759445837684 -- conda: https://prefix.dev/conda-forge/linux-64/secretstorage-3.3.3-py311h38be061_4.conda - sha256: 633a03b7bf6cd32cf2de2f349e968fbb8a14b46edb427ea83ba311a4868d5609 - md5: e8131ef5f338f7982dd93c0103687551 + size: 1414256 + timestamp: 1761848029452 +- conda: https://prefix.dev/conda-forge/linux-64/secretstorage-3.4.1-py311h38be061_0.conda + sha256: 47f28b12e760ae3ce8a1e616c5b56f5e874e0e4a036bdd09516ebf263c19521f + md5: ec955e67147942a68469a46d0bdf0a7b depends: - - cryptography + - cryptography >=2.0 - dbus - jeepney >=0.6 - python >=3.11,<3.12.0a0 @@ -4740,8 +4650,8 @@ packages: license_family: BSD purls: - pkg:pypi/secretstorage?source=hash-mapping - size: 32817 - timestamp: 1756916585609 + size: 32968 + timestamp: 1763045430433 - conda: https://prefix.dev/conda-forge/noarch/setuptools-80.9.0-pyhff2d567_0.conda sha256: 972560fcf9657058e3e1f97186cc94389144b46dbdf58c807ce62e83f977e863 md5: 4de79c071274a53dcaf2a8c749d1499e @@ -4753,17 +4663,17 @@ packages: - pkg:pypi/setuptools?source=hash-mapping size: 748788 timestamp: 1748804951958 -- conda: https://prefix.dev/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_1.conda - sha256: 0557c090913aa63cdbe821dbdfa038a321b488e22bc80196c4b3b1aace4914ef - md5: 7c3c2a0f3ebdea2bbc35538d162b43bf +- conda: https://prefix.dev/conda-forge/noarch/shellingham-1.5.4-pyhd8ed1ab_2.conda + sha256: 1d6534df8e7924d9087bd388fbac5bd868c5bf8971c36885f9f016da0657d22b + md5: 83ea3a2ddb7a75c1b09cea582aa4f106 depends: - - python >=3.9 + - python >=3.10 license: MIT license_family: MIT purls: - - pkg:pypi/shellingham?source=hash-mapping - size: 14462 - timestamp: 1733301007770 + - pkg:pypi/shellingham?source=compressed-mapping + size: 15018 + timestamp: 1762858315311 - conda: https://prefix.dev/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -4788,17 +4698,17 @@ packages: - pkg:pypi/snakeviz?source=hash-mapping size: 171545 timestamp: 1735289409501 -- conda: https://prefix.dev/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_1.conda - sha256: c2248418c310bdd1719b186796ae50a8a77ce555228b6acd32768e2543a15012 - md5: bf7a226e58dfb8346c70df36065d86c9 +- conda: https://prefix.dev/conda-forge/noarch/sniffio-1.3.1-pyhd8ed1ab_2.conda + sha256: dce518f45e24cd03f401cb0616917773159a210c19d601c5f2d4e0e5879d30ad + md5: 03fe290994c5e4ec17293cfb6bdce520 depends: - - python >=3.9 + - python >=3.10 license: Apache-2.0 license_family: Apache purls: - - pkg:pypi/sniffio?source=hash-mapping - size: 15019 - timestamp: 1733244175724 + - pkg:pypi/sniffio?source=compressed-mapping + size: 15698 + timestamp: 1762941572482 - conda: https://prefix.dev/conda-forge/linux-64/svt-av1-3.1.2-hecca717_0.conda sha256: 34e2e9c505cd25dba0a9311eb332381b15147cf599d972322a7c197aedfc8ce2 md5: 9859766c658e78fec9afa4a54891d920 @@ -4822,41 +4732,31 @@ packages: purls: [] size: 1474592 timestamp: 1756086729326 -- conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda - sha256: a84ff687119e6d8752346d1d408d5cf360dee0badd487a472aa8ddedfdc219e1 - md5: a0116df4f4ed05c303811a837d5b39d8 +- conda: https://prefix.dev/conda-forge/linux-64/tk-8.6.13-noxft_ha0e22de_103.conda + sha256: 1544760538a40bcd8ace2b1d8ebe3eb5807ac268641f8acdc18c69c5ebfeaf64 + md5: 86bc20552bf46075e3d92b67f089172d depends: - __glibc >=2.17,<3.0.a0 - libgcc >=13 - libzlib >=1.3.1,<2.0a0 + constrains: + - xorg-libx11 >=1.8.12,<2.0a0 license: TCL license_family: BSD purls: [] - size: 3285204 - timestamp: 1748387766691 -- conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_2.conda - sha256: cb86c522576fa95c6db4c878849af0bccfd3264daf0cc40dd18e7f4a7bfced0e - md5: 7362396c170252e7b7b0c8fb37fe9c78 + size: 3284905 + timestamp: 1763054914403 +- conda: https://prefix.dev/conda-forge/osx-arm64/tk-8.6.13-h892fb3f_3.conda + sha256: ad0c67cb03c163a109820dc9ecf77faf6ec7150e942d1e8bb13e5d39dc058ab7 + md5: a73d54a5abba6543cb2f0af1bfbd6851 depends: - __osx >=11.0 - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD purls: [] - size: 3125538 - timestamp: 1748388189063 -- conda: https://prefix.dev/conda-forge/noarch/tomli-2.2.1-pyhe01879c_2.conda - sha256: 040a5a05c487647c089ad5e05ad5aff5942830db2a4e656f1e300d73436436f1 - md5: 30a0a26c8abccf4b7991d590fe17c699 - depends: - - python >=3.9 - - python - license: MIT - license_family: MIT - purls: - - pkg:pypi/tomli?source=compressed-mapping - size: 21238 - timestamp: 1753796677376 + size: 3125484 + timestamp: 1763055028377 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.3.0-pyhcf101f3_0.conda sha256: cb77c660b646c00a48ef942a9e1721ee46e90230c7c570cdeb5a893b5cce9bff md5: d2732eb636c264dc9aa4cbee404b1a53 @@ -4891,9 +4791,9 @@ packages: - pkg:pypi/tomlkit?source=hash-mapping size: 38777 timestamp: 1749127286558 -- conda: https://prefix.dev/conda-forge/linux-64/tornado-6.5.2-py311h49ec1c0_1.conda - sha256: b1d686806d6b913e42aadb052b12d9cc91aae295640df3acfef645142fc33b3d - md5: 18a98f4444036100d78b230c94453ff4 +- conda: https://prefix.dev/conda-forge/linux-64/tornado-6.5.2-py311h49ec1c0_2.conda + sha256: 1913516458f92df2a0b415426dce27cc14922415787f4b672a707b233631b1e0 + md5: 8d7a63fc9653ed0bdc253a51d9a5c371 depends: - __glibc >=2.17,<3.0.a0 - libgcc >=14 @@ -4903,11 +4803,11 @@ packages: license_family: Apache purls: - pkg:pypi/tornado?source=hash-mapping - size: 868049 - timestamp: 1756855060036 -- conda: https://prefix.dev/conda-forge/osx-arm64/tornado-6.5.2-py311h3696347_1.conda - sha256: 4941963a1f0046b2813bfbe4c2ded15cb0b0048436fe62237d69467e8c0e1692 - md5: 25833dd6cb94341239aec42dd5370c33 + size: 869926 + timestamp: 1762506861961 +- conda: https://prefix.dev/conda-forge/osx-arm64/tornado-6.5.2-py311h9408147_2.conda + sha256: 70d4187bb8ec0016b9928e76eeaea0b2a021f741ea40a6ea2ee4b9c142ddaf24 + md5: e3af56f478d9919acac254ff82ad150c depends: - __osx >=11.0 - python >=3.11,<3.12.0a0 @@ -4917,30 +4817,19 @@ packages: license_family: Apache purls: - pkg:pypi/tornado?source=hash-mapping - size: 870380 - timestamp: 1756855179889 -- conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.8.26.11-pyhd8ed1ab_0.conda - sha256: c851abb1c9551ff189f392ca526fde04d2e33cc38b829718bc4560ce8ce73efe - md5: 7e40fb5d7eceaaf74900b3929dddfb06 + size: 869348 + timestamp: 1762507255364 +- conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.11.14.15-pyhd8ed1ab_0.conda + sha256: a99493b5d25272f160bfb4ef2b7878794dfa405ba9922bcee48b6f75675e3a74 + md5: e976edbb0821092956a85f1e7b627a97 depends: - python >=3.10 license: Apache-2.0 license_family: Apache purls: - pkg:pypi/trove-classifiers?source=hash-mapping - size: 19483 - timestamp: 1756214076961 -- conda: https://prefix.dev/conda-forge/noarch/trove-classifiers-2025.9.11.17-pyhd8ed1ab_0.conda - sha256: 74807fa88e811aeaf3d2acd6221665efd9469caf8c57b4ee370b61f0528ff0ae - md5: fc3b129397a910cfe1350075a7ad7432 - depends: - - python >=3.10 - license: Apache-2.0 - license_family: Apache - purls: - - pkg:pypi/trove-classifiers?source=compressed-mapping - size: 19575 - timestamp: 1757677773672 + size: 19522 + timestamp: 1763138400309 - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 md5: 0caa1af407ecff61170c9437a808404d @@ -4960,29 +4849,29 @@ packages: purls: [] size: 122968 timestamp: 1742727099393 -- conda: https://prefix.dev/conda-forge/linux-64/ukkonen-1.0.1-py311hd18a35c_5.conda - sha256: 4542cc3093f480c7fa3e104bfd9e5b7daeff32622121be6847f9e839341b0790 - md5: 4e8447ca8558a203ec0577b4730073f3 +- conda: https://prefix.dev/conda-forge/linux-64/ukkonen-1.0.1-py311hdf67eae_6.conda + sha256: a6201979b8619bb9122609eb2189287c33e4a75ad240e4880898941764022782 + md5: 57e703b0057f992687fb9ad154dc48e4 depends: - __glibc >=2.17,<3.0.a0 - cffi - - libgcc >=13 - - libstdcxx >=13 + - libgcc >=14 + - libstdcxx >=14 - python >=3.11,<3.12.0a0 - python_abi 3.11.* *_cp311 license: MIT license_family: MIT purls: - pkg:pypi/ukkonen?source=hash-mapping - size: 13858 - timestamp: 1725784165345 -- conda: https://prefix.dev/conda-forge/osx-arm64/ukkonen-1.0.1-py311h2c37856_5.conda - sha256: f48499c8f639265c53dc794ff2f2d0aa163845eb31841c226ec172f64861654d - md5: d5fe38d502e3d758c8f0fed8ba9ea652 + size: 14597 + timestamp: 1761594653571 +- conda: https://prefix.dev/conda-forge/osx-arm64/ukkonen-1.0.1-py311h57a9ea7_6.conda + sha256: b11dee8446a369aaa149b1650dec45105949c9043cc8a5802b292305d48b8718 + md5: 2534d14fa2ebc5a6657bc835bc695557 depends: - __osx >=11.0 - cffi - - libcxx >=17 + - libcxx >=19 - python >=3.11,<3.12.0a0 - python >=3.11,<3.12.0a0 *_cpython - python_abi 3.11.* *_cp311 @@ -4990,8 +4879,8 @@ packages: license_family: MIT purls: - pkg:pypi/ukkonen?source=hash-mapping - size: 13603 - timestamp: 1725784278728 + size: 14449 + timestamp: 1761595344417 - conda: https://prefix.dev/conda-forge/noarch/userpath-1.9.2-pyhd8ed1ab_0.conda sha256: 26e53b42f7fa1127e6115a35b91c20e15f75984648b88f115136f27715d4a440 md5: 946e3571aaa55e0870fec0dea13de3bf @@ -5004,23 +4893,23 @@ packages: - pkg:pypi/userpath?source=hash-mapping size: 14292 timestamp: 1735925027874 -- conda: https://prefix.dev/conda-forge/linux-64/uv-0.8.15-h2f8d451_0.conda - sha256: a03f08e7f19b91429592174183c9db1be5968bb92d0789bb39517149f4cd9965 - md5: 1a013fa5852b6b7b15bd954df41a5cc7 +- conda: https://prefix.dev/conda-forge/linux-64/uv-0.9.10-h76e24b7_0.conda + sha256: b926d266bce5f8c9734ecdfeab6739a06ca778771ab1739a549eb77227d8e952 + md5: 502e06bfb394fa379ad7bcea89f51e16 depends: + - libgcc >=14 - libstdcxx >=14 - libgcc >=14 - __glibc >=2.17,<3.0.a0 - - libgcc >=14 constrains: - __glibc >=2.17 license: Apache-2.0 OR MIT purls: [] - size: 16500799 - timestamp: 1756926254239 -- conda: https://prefix.dev/conda-forge/osx-arm64/uv-0.9.5-h194b5f9_0.conda - sha256: dba65bb5bbe44305af08f683962e27798b819d3ae55e559472edf3fcb37c0fba - md5: 45129b8b8240cbd14dbeccd97825f1f7 + size: 17090471 + timestamp: 1763412537330 +- conda: https://prefix.dev/conda-forge/osx-arm64/uv-0.9.10-h1bde295_0.conda + sha256: e369edaf12de310eda74694233862362381fd50c17afa2709f8ad26ed3f5e74b + md5: e27feb5e75c6277dfce3a775e8ed3fda depends: - __osx >=11.0 - libcxx >=19 @@ -5028,26 +4917,11 @@ packages: - __osx >=11.0 license: Apache-2.0 OR MIT purls: [] - size: 14915379 - timestamp: 1761083102340 -- conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.34.0-pyhd8ed1ab_0.conda - sha256: 398f40090e80ec5084483bb798555d0c5be3d1bb30f8bb5e4702cd67cdb595ee - md5: 2bd6c0c96cfc4dbe9bde604a122e3e55 - depends: - - distlib >=0.3.7,<1 - - filelock >=3.12.2,<4 - - platformdirs >=3.9.1,<5 - - python >=3.9 - - typing_extensions >=4.13.2 - license: MIT - license_family: MIT - purls: - - pkg:pypi/virtualenv?source=compressed-mapping - size: 4381624 - timestamp: 1755111905876 -- conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.35.3-pyhd8ed1ab_0.conda - sha256: af9662662648f7f57c0a79afee98e393dacf68887c40aea1eec68b48afebb724 - md5: bf0dc4c8a32e91290e3fae5403798c63 + size: 14815480 + timestamp: 1763412481324 +- conda: https://prefix.dev/conda-forge/noarch/virtualenv-20.35.4-pyhd8ed1ab_0.conda + sha256: 77193c99c6626c58446168d3700f9643d8c0dab1f6deb6b9dd039e6872781bfb + md5: cfccfd4e8d9de82ed75c8e2c91cab375 depends: - distlib >=0.3.7,<1 - filelock >=3.12.2,<4 @@ -5058,34 +4932,34 @@ packages: license_family: MIT purls: - pkg:pypi/virtualenv?source=compressed-mapping - size: 4380205 - timestamp: 1760134237380 -- conda: https://prefix.dev/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda - sha256: ba673427dcd480cfa9bbc262fd04a9b1ad2ed59a159bd8f7e750d4c52282f34c - md5: 0f2ca7906bf166247d1d760c3422cb8a + size: 4401341 + timestamp: 1761726489722 +- conda: https://prefix.dev/conda-forge/linux-64/wayland-1.24.0-hd6090a7_1.conda + sha256: 3aa04ae8e9521d9b56b562376d944c3e52b69f9d2a0667f77b8953464822e125 + md5: 035da2e4f5770f036ff704fa17aace24 depends: - __glibc >=2.17,<3.0.a0 - - libexpat >=2.7.0,<3.0a0 - - libffi >=3.4.6,<3.5.0a0 - - libgcc >=13 - - libstdcxx >=13 + - libexpat >=2.7.1,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - libstdcxx >=14 license: MIT license_family: MIT purls: [] - size: 330474 - timestamp: 1751817998141 -- conda: https://prefix.dev/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda - sha256: a5d4af601f71805ec67403406e147c48d6bad7aaeae92b0622b7e2396842d3fe - md5: 397a013c2dc5145a70737871aaa87e98 + size: 329779 + timestamp: 1761174273487 +- conda: https://prefix.dev/conda-forge/linux-64/xkeyboard-config-2.46-hb03c661_0.conda + sha256: aa03b49f402959751ccc6e21932d69db96a65a67343765672f7862332aa32834 + md5: 71ae752a748962161b4740eaff510258 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 - xorg-libx11 >=1.8.12,<2.0a0 license: MIT license_family: MIT purls: [] - size: 392406 - timestamp: 1749375847832 + size: 396975 + timestamp: 1759543819846 - conda: https://prefix.dev/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda sha256: c12396aabb21244c212e488bbdc4abcdef0b7404b15761d9329f5a4a39113c4b md5: fb901ff28063514abb6046c9ec2c4a45 @@ -5122,17 +4996,17 @@ packages: purls: [] size: 835896 timestamp: 1741901112627 -- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda - sha256: ed10c9283974d311855ae08a16dfd7e56241fac632aec3b92e3cfe73cff31038 - md5: f6ebe2cb3f82ba6c057dde5d9debe4f7 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda + sha256: 6bc6ab7a90a5d8ac94c7e300cc10beb0500eeba4b99822768ca2f2ef356f731b + md5: b2895afaf55bf96a8c8282a2e47a5de0 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 14780 - timestamp: 1734229004433 + size: 15321 + timestamp: 1762976464266 - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda sha256: 753f73e990c33366a91fd42cc17a3d19bb9444b9ca5ff983605fa9e953baf57f md5: d3c295b50f092ab525ffe3c2aa4b7413 @@ -5174,17 +5048,17 @@ packages: purls: [] size: 13217 timestamp: 1727891438799 -- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda - sha256: 6b250f3e59db07c2514057944a3ea2044d6a8cdde8a47b6497c254520fade1ee - md5: 8035c64cb77ed555e3f150b7b3972480 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda + sha256: 25d255fb2eef929d21ff660a0c687d38a6d2ccfbcbf0cc6aa738b12af6e9d142 + md5: 1dafce8548e38671bea82e3f5c6ce22f depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 + - libgcc >=14 license: MIT license_family: MIT purls: [] - size: 19901 - timestamp: 1727794976192 + size: 20591 + timestamp: 1762976546182 - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda sha256: da5dc921c017c05f38a38bd75245017463104457b63a1ce633ed41f214159c14 md5: febbab7d15033c913d53c7a2c102309d @@ -5197,18 +5071,18 @@ packages: purls: [] size: 50060 timestamp: 1727752228921 -- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda - sha256: 2fef37e660985794617716eb915865ce157004a4d567ed35ec16514960ae9271 - md5: 4bdb303603e9821baf5fe5fdff1dc8f8 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda + sha256: 83c4c99d60b8784a611351220452a0a85b080668188dce5dfa394b723d7b64f4 + md5: ba231da7fccf9ea1e768caf5c7099b84 depends: - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - xorg-libx11 >=1.8.10,<2.0a0 + - libgcc >=14 + - xorg-libx11 >=1.8.12,<2.0a0 license: MIT license_family: MIT purls: [] - size: 19575 - timestamp: 1727794961233 + size: 20071 + timestamp: 1759282564045 - conda: https://prefix.dev/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda sha256: 1a724b47d98d7880f26da40e45f01728e7638e6ec69f35a3e11f92acd05f9e7a md5: 17dcc85db3c7886650b8908b183d6876 @@ -5290,6 +5164,30 @@ packages: purls: [] size: 32808 timestamp: 1727964811275 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-libxxf86vm-1.1.6-hb9d3cd8_0.conda + sha256: 8a4e2ee642f884e6b78c20c0892b85dd9b2a6e64a6044e903297e616be6ca35b + md5: 5efa5fa6243a622445fdfd72aee15efa + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 17819 + timestamp: 1734214575628 +- conda: https://prefix.dev/conda-forge/linux-64/xorg-xorgproto-2024.1-hb9d3cd8_1.conda + sha256: 1316680be6edddee0156b86ec1102fc8286f51c1a5440366ed1db596a2dc3731 + md5: 7c21106b851ec72c037b162c216d8f05 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 565425 + timestamp: 1726846388217 - conda: https://prefix.dev/conda-forge/linux-64/xz-5.8.1-hbcc6ac9_2.conda sha256: 802725371682ea06053971db5b4fb7fbbcaee9cb1804ec688f55e51d74660617 md5: 68eae977d7d1196d32b636a026dc015d @@ -5422,40 +5320,40 @@ packages: purls: [] size: 77606 timestamp: 1727963209370 -- conda: https://prefix.dev/conda-forge/linux-64/zstandard-0.24.0-py311h4854a17_1.conda - sha256: 0c13155c0eaeda24d1b208a4e9af28db025fd3388eca05fec872ce8d155d4e26 - md5: d0d623c1cd5a9515de1b2260d21a92aa +- conda: https://prefix.dev/conda-forge/linux-64/zstandard-0.25.0-py311haee01d2_1.conda + sha256: d534a6518c2d8eccfa6579d75f665261484f0f2f7377b50402446a9433d46234 + md5: ca45bfd4871af957aaa5035593d5efd2 depends: - - __glibc >=2.17,<3.0.a0 + - python - cffi >=1.11 - - libgcc >=14 - - python >=3.11,<3.12.0a0 - - python_abi 3.11.* *_cp311 - zstd >=1.5.7,<1.5.8.0a0 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD purls: - - pkg:pypi/zstandard?source=compressed-mapping - size: 426304 - timestamp: 1756841168805 -- conda: https://prefix.dev/conda-forge/osx-arm64/zstandard-0.25.0-py311h5bb9006_0.conda - sha256: fb1443a1479a6d709b4af7a2cdcea3ef2a5e859378de19814086fa86ca6f934e - md5: c7e0f1b714bd12d39899a4f0c296dd86 + - pkg:pypi/zstandard?source=hash-mapping + size: 466893 + timestamp: 1762512695614 +- conda: https://prefix.dev/conda-forge/osx-arm64/zstandard-0.25.0-py311h5bb9006_1.conda + sha256: 2ee455765fe831cca8fe127c56ae99938e353797135fe33140b28abb4fbe1049 + md5: 651594b8f9b9cccc5948287a18903c34 depends: - python - cffi >=1.11 - zstd >=1.5.7,<1.5.8.0a0 - - __osx >=11.0 - python 3.11.* *_cpython - - zstd >=1.5.7,<1.6.0a0 + - __osx >=11.0 - python_abi 3.11.* *_cp311 + - zstd >=1.5.7,<1.6.0a0 license: BSD-3-Clause license_family: BSD purls: - pkg:pypi/zstandard?source=hash-mapping - size: 390089 - timestamp: 1757930124840 + size: 390026 + timestamp: 1762512731928 - conda: https://prefix.dev/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda sha256: a4166e3d8ff4e35932510aaff7aa90772f84b4d07e9f6f83c614cba7ceefe0eb md5: 6432cb5d4ac0046c3ac0a8a0f95842f9 diff --git a/pyproject.toml b/pyproject.toml index 55b2722a..762fe35b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,11 @@ authors = [ { name = "Hamish Starling", email = "hamish.starling22@imperial.ac.uk" }, { name = "Luke Moran", email = "luke.moran22@imperial.ac.uk" }, { name = "Sadig Sadikhzada", email = "sadig.sadikhzada23@imperial.ac.uk" }, - { name = "Li Han", email = "han.li124@imperial.ac.uk" } + { name = "Li Han", email = "han.li124@imperial.ac.uk" }, + { name = "Valentin Bruhl", email = "valentin.bruhl24@imperial.ac.uk" }, + { name = "Sarthak Agarwal", email = "sarthak.agarwal25@imperial.ac.uk" }, + { name = "Low Sze Yoong", email = "szeyoong.low25@imperial.ac.uk" }, + { name = "Jiaming Liu", email = "jiaming.liu25@imperial.ac.uk" }, ] requires-python = ">=3.11" diff --git a/utama_core/global_utils/math_utils.py b/utama_core/global_utils/math_utils.py index a6eeefd0..926f2b93 100644 --- a/utama_core/global_utils/math_utils.py +++ b/utama_core/global_utils/math_utils.py @@ -56,7 +56,7 @@ def normalise_heading_deg(angle): The normalized angle in the range [-180, 180] degrees. """ half_rev = 180 - + return (angle + half_rev) % (2 * half_rev) - half_rev diff --git a/utama_core/rsoccer_simulator/src/ssl/envs/standard_ssl.py b/utama_core/rsoccer_simulator/src/ssl/envs/standard_ssl.py index b1bb4de3..58faf973 100644 --- a/utama_core/rsoccer_simulator/src/ssl/envs/standard_ssl.py +++ b/utama_core/rsoccer_simulator/src/ssl/envs/standard_ssl.py @@ -1,8 +1,9 @@ import logging -from numpy.random import normal import random from typing import List, Tuple +from numpy.random import normal + from utama_core.config.formations import LEFT_START_ONE, RIGHT_START_ONE from utama_core.config.robot_params import RSIM_PARAMS from utama_core.config.settings import ( @@ -13,11 +14,15 @@ ) from utama_core.entities.data.command import RobotResponse from utama_core.entities.data.raw_vision import RawBallData, RawRobotData, RawVisionData -from utama_core.global_utils.math_utils import deg_to_rad, rad_to_deg, normalise_heading_deg +from utama_core.global_utils.math_utils import ( + deg_to_rad, + normalise_heading_deg, + rad_to_deg, +) from utama_core.rsoccer_simulator.src.Entities import Ball, Frame, Robot from utama_core.rsoccer_simulator.src.ssl.ssl_gym_base import SSLBaseEnv -from utama_core.rsoccer_simulator.src.Utils.gaussian_noise import RsimGaussianNoise from utama_core.rsoccer_simulator.src.Utils import KDTree +from utama_core.rsoccer_simulator.src.Utils.gaussian_noise import RsimGaussianNoise logger = logging.getLogger(__name__) @@ -38,19 +43,19 @@ class SSLStandardEnv(SSLBaseEnv): Description: list of (x, y, theta) coords for each robot to spawn in (in meters and radians). See the default BLUE_START_ONE/YELLOW_START_ONE for reference. - + gaussian_noise Type: RsimGaussianNoise Description: When running in rsim, add Gaussian noise to ball and robots with the given standard deviations. Mutates the Robot object in place. The 3 parameters are for x (in m), y (in m), and orientation (in degrees) respectively. Defaults to 0 for each. - + vanishing Type: float Description: When running in rsim, cause robots and ball to vanish with the given probability. Defaults to 0. - + Observation: Type: Tuple[FrameData, List[RobotInfo], List[RobotInfo]] Num Item @@ -78,7 +83,7 @@ def __init__( blue_starting_formation: list[tuple] = None, yellow_starting_formation: list[tuple] = None, gaussian_noise: RsimGaussianNoise = RsimGaussianNoise(), - vanishing: float = 0 + vanishing: float = 0, ): super().__init__( field_type=field_type, @@ -108,11 +113,11 @@ def __init__( self.latest_observation = (-1, None) logger.info(f"{n_robots_blue}v{n_robots_yellow} SSL Environment Initialized") - + # Adding Gaussian noise and vanishing. Refer to StrategyRunner self.gaussian_noise = gaussian_noise - - assert vanishing >= 0 + + assert vanishing >= 0, "Negative vanishing probability not allowed" self.vanishing = vanishing def reset(self, *, seed=None, options=None): @@ -172,7 +177,7 @@ def _frame_to_observations( yellow_robots_info: feedback from individual yellow robots that returns a List[RobotInfo] blue_robots_info: feedback from individual blue robots that returns a List[RobotInfo] """ - + if self.latest_observation[0] == self.steps: return self.latest_observation[1] @@ -189,7 +194,7 @@ def _frame_to_observations( for i in range(len(self.frame.robots_blue)): if self._vanishing(): continue - + robot = self.frame.robots_blue[i] robot_pos, robot_info = self._get_robot_observation(robot) blue_obs.append(robot_pos) @@ -200,7 +205,7 @@ def _frame_to_observations( for i in range(len(self.frame.robots_yellow)): if self._vanishing(): continue - + robot = self.frame.robots_yellow[i] robot_pos, robot_info = self._get_robot_observation(robot) yellow_obs.append(robot_pos) @@ -221,7 +226,7 @@ def _frame_to_observations( def _get_robot_observation(self, robot): SSLStandardEnv._add_gaussian_noise_robot(robot, self.gaussian_noise) - + robot_pos = RawRobotData(robot.id, robot.x, -robot.y, -float(deg_to_rad(robot.theta)), 1) robot_info = RobotResponse(robot.id, robot.infrared) return robot_pos, robot_info @@ -415,47 +420,45 @@ def in_gk_area(obj): return pos_frame - def _vanishing(self) -> bool: """Determines whether a frame should vanish. Only runs after Game Gater is passed""" return self.steps > 0 and self.vanishing and (random.random() < self.vanishing) - @staticmethod def _add_gaussian_noise_ball(ball: Ball, noise: RsimGaussianNoise): """ When running in rsim, add Gaussian noise to ball with the given standard deviations. Mutates the Robot object in place. - + Args: noise (RsimGaussianNoise): The 3 parameters are for x (in m), y (in m), and orientation (in degrees) respectively. Defaults to 0 for each. """ - + if noise.x_stddev: ball.x += normal(scale=noise.x_stddev) - + if noise.y_stddev: ball.y += normal(scale=noise.y_stddev) - + # No noise addition for z, since rSim is 2-D - + @staticmethod def _add_gaussian_noise_robot(robot: Robot, noise: RsimGaussianNoise): """ When running in rsim, add Gaussian noise to robot with the given standard deviations. Mutates the Robot object in place. - + Args: noise (RsimGaussianNoise): The 3 parameters are for x (in m), y (in m), and orientation (in degrees) respectively. Defaults to 0 for each. """ - + if noise.x_stddev: robot.x += normal(scale=noise.x_stddev) - + if noise.y_stddev: robot.y += normal(scale=noise.y_stddev) - + if noise.th_stddev_deg: - robot.theta = normalise_heading_deg(robot.theta + normal(scale=noise.th_stddev_deg)) \ No newline at end of file + robot.theta = normalise_heading_deg(robot.theta + normal(scale=noise.th_stddev_deg)) diff --git a/utama_core/run/refiners/kalman.py b/utama_core/run/refiners/kalman.py new file mode 100644 index 00000000..5579a882 --- /dev/null +++ b/utama_core/run/refiners/kalman.py @@ -0,0 +1,404 @@ +from typing import Optional + +import numpy as np + +from utama_core.entities.data.vector import Vector3D +from utama_core.entities.data.vision import VisionRobotData +from utama_core.entities.game import Ball, Robot +from utama_core.global_utils.math_utils import deg_to_rad, normalise_heading + + +class KalmanFilter: + """ + Kalman filter for 2D position and orientation of robots. + + It works in 2 phases: + 1. Prediction: The object's last known velocity and kinematics formulae are + used to estimate its current position. (Orientation is assumed to be constant + due to a lack of data on angular velocity.) + + 2. Updating: New vision data is used to update the filter's estimate. The + information is weighed using the Kalman gain, a constant that depends on + the system's noise level. + + If no data is received, the filter's prediction is used. + + Note: The filter's parameters are the standard deviations of random noise. + The rsim noise generator also uses standard deviation, so the optimal parameter + should be the same as the argument to it. Do not use variance (standard deviation squared). + + More about the methodology and formulae used can be found at https://kalmanfilter.net/. + + Args: + id (int): The associated robot's ID, used for associating the filter + with the robot. Defaults to 0. + + noise_xy_sd (float): A hyper-parameter, used to weigh the filter's + predictions and the vision data received during the "update" phase. + Unit is metres. + Defaults to 0.01 (In simulation, this should match the argument + passed to the rsim noise generator, but should be adjusted based on + real-world conditions when live robots are used). + + noise_th_sd_deg (float): A hyper-parameter, used to weigh the filter's + predictions and the vision data received during the "update" phase. + Unit is degrees. Conversion to radians is done internally. + Defaults to 5 (In simulation, this should match the argument + passed to the rsim noise generator, but should be adjusted based on + real-world conditions when live robots are used). + """ + + def __init__(self, id: int = 0, noise_xy_sd: float = 0.01, noise_th_sd_deg: float = 5): + assert noise_xy_sd > 0, "The standard deviation must be greater than 0" + assert noise_th_sd_deg > 0, "The standard deviation must be greater than 0" + + self.id = id + + # For position + # s; to be initialised by strategy runner with 1st GameFrame + self.state_xy = None + + # sigma squared x, sigma squared y + noise_xy_var = pow(noise_xy_sd, 2) + var_x, var_y = noise_xy_var, noise_xy_var + + # sigma xy; assume their errors are uncorrelated + covariance_xy = 0 + + dimensions_xy = 2 + self.identity_xy = np.identity(dimensions_xy) + + # R_n + self.measurement_cov_xy = np.array([[var_x, covariance_xy], [covariance_xy, var_y]]) + # P_n,n; initialised with uncertainty in 1st frame + self.covariance_mat_xy = self.measurement_cov_xy + # Q + self.process_noise_xy = (2 * noise_xy_var) * self.identity_xy + + # Observation matrix H and state transition matrix F are just the identity matrix. + # Multiplications with them are omitted. + + # For orientation + # s; to be initialised by strategy runner with 1st GameFrame + self.state_th = None + + # sigma squared th + noise_th_var = pow(deg_to_rad(noise_th_sd_deg), 2) + + # r_n + self.measurement_cov_th = noise_th_var + # p_n,n; initialised with uncertainty in 1st frame + self.covariance_th = noise_th_var + # q + self.process_noise_th = noise_th_var + + def _step_xy( + self, + new_data: Optional[tuple[float, float]], + last_robot: Robot, + time_elapsed: float, + ) -> tuple[float, float]: + """ + A single iteration of the filter for x and y coordinates. + + Args: + new_data (tuple[float, float]): New vision data received (x coordinates in metres, y coordinates in metres), + passed by filter_data. + last_robot (Robot): An object storing the robot's last known position and velocity, among others. + time_elapsed (float): Time since last vision data was received. + + Returns: + tuple[float, float]: Filtered vision data (x coordinates, y coordinates), + returned to filter_data for packaging. + + """ + + # class Robot: id: int; is_friendly: bool; has_ball: bool + # p: Vector2D; v: Vector2D; a: Vector2D; orientation: float + + # Phase 0: Initialised with the 1st valid GameFrame (only on initialisation) + if self.state_xy is None: + self.state_xy = np.array((last_robot.p.x, last_robot.p.y)) + + # Phase 1: Predicting the current state given the last state. + # u + control_velocities_xy = np.array((last_robot.v.x, last_robot.v.y)) + # G + control_mat_xy = time_elapsed * self.identity_xy + + # s_n,n-1 + pred_state_xy = self.state_xy + np.matmul(control_mat_xy, control_velocities_xy) + # P_n,n-1 + pred_cov_xy = self.covariance_mat_xy + self.process_noise_xy + + # Phase 2: Adjust this prediction based on new data + if new_data is not None: # Received frame. + # z + measurement_xy = np.array(new_data) + + # K_n + kalman_gain_xy = np.linalg.solve((pred_cov_xy + self.measurement_cov_xy).T, pred_cov_xy.T).T + + # s_n,n + self.state_xy = pred_state_xy + np.matmul(kalman_gain_xy, (measurement_xy - pred_state_xy)) + + ident_less_kalman_xy = self.identity_xy - kalman_gain_xy + measurement_uncertainty_xy = np.matmul( + kalman_gain_xy, + np.matmul(self.measurement_cov_xy, kalman_gain_xy.T), + ) + + # P_n,n + self.covariance_mat_xy = ( + np.matmul(ident_less_kalman_xy, np.matmul(pred_cov_xy, ident_less_kalman_xy.T)) + + measurement_uncertainty_xy + ) + + # We can rely on the invariant that vanished frames have null x values + # as they are imputed with a null VisionRobotData in the Position Refiner. + else: # Vanished frame: use predicted values. + self.state_xy = pred_state_xy + self.covariance_mat_xy = pred_cov_xy + + return tuple(self.state_xy) + + def _step_th(self, new_data: Optional[float], last_th: float) -> float: + """ + A single iteration of the filter for orientation. + + Args: + new_data (float): New vision data received (orientation in radians), + passed by the externally callable function filter_data. + last_th (float): The robot's last known orientation + + Returns: + float: Filtered vision data orientation, + returned to filter_data for packaging. + + """ + + # Phase 0: Initialised with the 1st valid GameFrame (only on initialisation) + if self.state_th is None: + self.state_th = last_th + + # Phase 1: Predicting the current state given the last state. + # s_n,n-1 = s_n-1,n-1 (Assuming constant velocity) + # P_n,n-1 + pred_cov_th = self.covariance_th + self.process_noise_th + + # Phase 2: Adjust this prediction based on new data + if new_data is not None: # Received frame. + # z + measurement_th = normalise_heading(new_data) + + # K_n + kalman_gain_th = pred_cov_th / (pred_cov_th + self.measurement_cov_th) + + # Taking a circular weighted average + weights_th = (kalman_gain_th, 1 - kalman_gain_th) + values_th = (measurement_th, self.state_th) + sines_th = np.dot(weights_th, np.sin(values_th)) + cosines_th = np.dot(weights_th, np.cos(values_th)) + # s_n,n; already wrapped to (-pi, pi] as we're taking a circular average + self.state_th = float(np.arctan2(sines_th, cosines_th)) + + # P_n,n + self.covariance_th = (1 - kalman_gain_th) * pred_cov_th + + # We can rely on the invariant that vanished frames have null x values + # as they are imputed with a null VisionRobotData in the Position Refiner. + else: # Vanished frame: use predicted values. + # self.state_th is unchanged + self.covariance_th = pred_cov_th + + return self.state_th + + def filter_data( + self, + data: Optional[VisionRobotData], + last_frame: Robot, + time_elapsed: float, + ) -> VisionRobotData: + """ + Performs one prediction–update cycle of the Kalman filter for the + associated robot. + + The robot's state is first predicted using its last known velocity and + the elapsed time. If new vision data is available, the prediction is + corrected using the Kalman gain. If the vision frame is missing, the + predicted state is used directly. + + Args: + data (VisionRobotData): New vision measurement containing position + (x, y) in metres and orientation in radians. + last_frame (dict[int, Robot]): Mapping of robot IDs to their last + known state (position, velocity, orientation), used for motion + prediction. + time_elapsed (float): Time in seconds since the previous update. + + Returns: + VisionRobotData: Filtered estimate of the robot's position (x, y) + and orientation, packaged as a VisionRobotData object. + """ + + # class VisionRobotData: id: int; x: float; y: float; orientation: float + xy_tuple = (data.x, data.y) if data is not None else None + x_f, y_f = self._step_xy(xy_tuple, last_frame, time_elapsed) + th_f = self._step_th( + data.orientation if data is not None else None, + last_frame.orientation, + ) + + return VisionRobotData(self.id, x_f, y_f, th_f) + + +class KalmanFilterBall: + """ + Kalman filter for 3D position of ball. + + See above for details about the methodology. + + Args: + noise_sd (float): A hyper-parameter, used to weigh the filter's + predictions and the vision data received during the "update" phase. + Unit is metres. + Defaults to 0.01 (In simulation, this should match the argument + passed to the rsim noise generator, but should be adjusted based on + real-world conditions when live robots are used). + """ + + def __init__(self, noise_sd: float = 0.01): + assert noise_sd > 0, "The standard deviation must be greater than 0" + + # s; to be initialised by strategy runner with 1st GameFrame + self.state = None + + # sigma squared x, y, z + noise_var = pow(noise_sd, 2) + var_x, var_y, var_z = noise_var, noise_var, noise_var + + # sigma xy, xz, yz + noise_covariance = 0 # assume their errors are uncorrelated + covariance_xy, covariance_xz, covariance_yz = ( + noise_covariance, + noise_covariance, + noise_covariance, + ) + + dimensions = 3 + self.identity = np.identity(dimensions) + + # R_n + self.measurement_cov = np.array( + [ + [var_x, covariance_xy, covariance_xz], + [covariance_xy, var_y, covariance_yz], + [covariance_xz, covariance_yz, var_z], + ] + ) + # P_n,n; initialised with uncertainty in 1st frame + self.covariance_mat = self.measurement_cov + # Q + self.process_noise = (2 * noise_var) * self.identity + + # Observation matrix H and state transition matrix F are just the identity matrix. + # Multiplications with them are omitted. + + def _step( + self, + new_data: Optional[tuple[float, float, float]], + last_ball: Ball, + time_elapsed: float, + ) -> tuple[float, float, float]: + """ + A single iteration of the filter. + + Args: + new_data (Optional[tuple[float, float, float]]): New vision data received (xyz coordinates in metres), + passed by the filter_data function. None if the ball is not detected. + last_ball (Ball): An object storing the ball's last known position and velocity. + time_elapsed (float): Time since last vision data was received. + + Returns: + tuple[float, float, float]: Filtered vision data (xyz coordinates), + returned to the filter_data function for packaging. + """ + + # class Ball: p: Vector3D; v: Vector3D; a: Vector3D + + # Phase 0: Initialised with the 1st valid GameFrame (only on initialisation) + if self.state is None: + self.state = np.array((last_ball.p.x, last_ball.p.y, last_ball.p.z)) + + # Phase 1: Predicting the current state given the last state. + # u + control_velocities = np.array((last_ball.v.x, last_ball.v.y, last_ball.v.z)) + # G + control_mat = time_elapsed * self.identity + # s_n,n-1 + pred_state = self.state + np.matmul(control_mat, control_velocities) + # P_n,n-1 + pred_cov = self.covariance_mat + self.process_noise + + # Phase 2: Adjust this prediction based on new data + if new_data is not None: # Received frame. + # z + measurement = np.array(new_data) + + # K_n + kalman_gain = np.linalg.solve((pred_cov + self.measurement_cov).T, pred_cov.T).T + + # s_n,n + self.state = pred_state + np.matmul(kalman_gain, (measurement - pred_state)) + + ident_less_kalman = self.identity - kalman_gain + measurement_uncertainty = np.matmul(kalman_gain, np.matmul(self.measurement_cov, kalman_gain.T)) + + # P_n,n + self.covariance_mat = ( + np.matmul(ident_less_kalman, np.matmul(pred_cov, ident_less_kalman.T)) + measurement_uncertainty + ) + + # We can rely on the invariant that vanished frames have null x values + # as they are imputed with None by filter_data + else: # Vanished frame: use predicted values. + self.state = pred_state + self.covariance_mat = pred_cov + + return tuple(self.state) + + def filter_data(self, data: Optional[Ball], last_frame: Ball, time_elapsed: float) -> Ball: + """ + Performs one prediction–update cycle of the Kalman filter for the ball. + + The ball's position is first predicted using its last known velocity + and the elapsed time. If new vision data is available, the prediction + is corrected using the Kalman gain. If the vision frame is missing, + the predicted state is used directly. + + Args: + data (Optional[Ball]): New vision measurement containing the ball's position + (x, y, z) in metres. May be None if the ball is not detected. + last_frame (Ball): The ball's last known state, including position, + velocity, and acceleration, used for motion prediction. + time_elapsed (float): Time in seconds since the previous update. + + Returns: + Ball: Filtered estimate of the ball's position, returned as a Ball + object with updated position and preserved velocity and + acceleration. + """ + + # class Ball: p: Vector3D, v: Vector3D, a: Vector3D + if data is not None: + new_data = (data.p.x, data.p.y, data.p.z) + velocity, acceleration = data.v, data.a + else: + # If the ball data vanished, PositionRefiner._get_most_confident_ball returns null. + new_data = None + zero_vector = Vector3D(0, 0, 0) + velocity, acceleration = zero_vector, zero_vector + + filtered_data = self._step(new_data, last_frame, time_elapsed) + + return Ball(Vector3D(*filtered_data), velocity, acceleration) diff --git a/utama_core/run/refiners/position.py b/utama_core/run/refiners/position.py index 661c8681..b2a5ee3f 100644 --- a/utama_core/run/refiners/position.py +++ b/utama_core/run/refiners/position.py @@ -1,256 +1,390 @@ -from collections import defaultdict -from dataclasses import replace -from typing import Dict, List, Optional, Tuple - -import numpy as np - -from utama_core.config.settings import BALL_MERGE_THRESHOLD -from utama_core.entities.data.raw_vision import RawBallData, RawRobotData, RawVisionData -from utama_core.entities.data.vector import Vector2D, Vector3D -from utama_core.entities.data.vision import VisionBallData, VisionData, VisionRobotData -from utama_core.entities.game import Ball, FieldBounds, GameFrame, Robot -from utama_core.run.refiners.base_refiner import BaseRefiner - - -class AngleSmoother: - def __init__(self, alpha=0.3): - self.alpha = alpha # Smoothing factor for angle - self.smoothed_angles = {} # Stores last smoothed angle for each robot - - def smooth(self, old_angle: float, new_angle: float) -> float: - # Compute the shortest angular difference - diff = np.atan2(np.sin(new_angle - old_angle), np.cos(new_angle - old_angle)) - smoothed_angle = old_angle + self.alpha * diff - - return smoothed_angle - - -class PositionRefiner(BaseRefiner): - def __init__(self, field_bounds: FieldBounds, bounds_buffer: float = 1.0): - # alpha=0 means no change in angle (inf smoothing), alpha=1 means no smoothing - self.angle_smoother = AngleSmoother(alpha=1) - self.x_min = field_bounds.top_left[0] - bounds_buffer # expand left - self.x_max = field_bounds.bottom_right[0] + bounds_buffer # expand right - self.y_min = field_bounds.bottom_right[1] - bounds_buffer # expand bottom - self.y_max = field_bounds.top_left[1] + bounds_buffer # expand top - self.BOUNDS_BUFFER = bounds_buffer - - # Primary function for the Refiner interface - def refine(self, game_frame: GameFrame, data: List[RawVisionData]) -> GameFrame: - frames = [frame for frame in data if frame is not None] - - # If no information just return the original - # TODO: this needs to be replaced by an extrapolation function (otherwise we will be using old data forever) - if not frames: - return game_frame - # Can combine previous position from game with new data to produce new position if desired - combined_vision_data = CameraCombiner().combine_cameras(frames) - - # for robot in combined_vision_data.yellow_robots: - # if robot.id == 0: - # print(f"robot orientation: {robot.orientation}") - - new_yellow_robots, new_blue_robots = self._combine_both_teams_game_vision_positions( - game_frame, - combined_vision_data.yellow_robots, - combined_vision_data.blue_robots, - ) - - # After the balls have been combined, take the most confident - new_ball = PositionRefiner._get_most_confident_ball(combined_vision_data.balls) - if new_ball is None: - # If none, take the ball from the last frame of the game - new_ball = game_frame.ball - - if game_frame.my_team_is_yellow: - new_game_frame = replace( - game_frame, - ts=combined_vision_data.ts, - friendly_robots=new_yellow_robots, - enemy_robots=new_blue_robots, - ball=new_ball, - ) - else: - new_game_frame = replace( - game_frame, - ts=combined_vision_data.ts, - friendly_robots=new_blue_robots, - enemy_robots=new_yellow_robots, - ball=new_ball, - ) - return new_game_frame - - # Static methods - @staticmethod - def _combine_robot_vision_data( - old_robot: Robot, robot_data: VisionRobotData, angle_smoother: AngleSmoother - ) -> Robot: - assert old_robot.id == robot_data.id - new_x, new_y = robot_data.x, robot_data.y - - # Needs fixing the bounds are off oren becoming -3.9rad - # # Smoothing - # new_orientation = angle_smoother.smooth( - # old_robot.orientation, robot_data.orientation - # ) - return replace( - old_robot, - id=robot_data.id, - p=Vector2D(new_x, new_y), - orientation=robot_data.orientation, - ) - - # Used at start of the game so assume robot does not have the ball - # Also assume velocity and acceleration are zero - @staticmethod - def _robot_from_vision(robot_data: VisionRobotData, is_friendly: bool) -> Robot: - return Robot( - id=robot_data.id, - is_friendly=is_friendly, - has_ball=False, - p=Vector2D(robot_data.x, robot_data.y), - v=Vector2D(0, 0), - a=Vector2D(0, 0), - orientation=robot_data.orientation, - ) - - @staticmethod - def _ball_from_vision(ball_data: VisionBallData) -> Ball: - zv = Vector3D(0, 0, 0) - return Ball(Vector3D(ball_data.x, ball_data.y, ball_data.z), zv, zv) - - @staticmethod - def _get_most_confident_ball(balls: List[VisionBallData]) -> Ball: - balls_by_confidence = sorted(balls, key=lambda ball: ball.confidence, reverse=True) - if not balls_by_confidence: - return None - return PositionRefiner._ball_from_vision(balls_by_confidence[0]) - - def _combine_single_team_positions( - self, - new_game_robots: Dict[int, Robot], - vision_robots: List[VisionRobotData], - friendly: bool, - ) -> Dict[int, Robot]: - for robot in vision_robots: - new_x, new_y = robot.x, robot.y - - if not (self.x_min <= new_x <= self.x_max and self.y_min <= new_y <= self.y_max): - # Out of bounds so ignore this robot - continue - - if robot.id not in new_game_robots: - # At the start of the game, we haven't seen anything yet, so just create a new robot - new_game_robots[robot.id] = PositionRefiner._robot_from_vision(robot, is_friendly=friendly) - else: - # Update with smoothed data. - new_game_robots[robot.id] = PositionRefiner._combine_robot_vision_data( - new_game_robots[robot.id], robot, self.angle_smoother - ) - return new_game_robots - - def _combine_both_teams_game_vision_positions( - self, - game_frame: GameFrame, - yellow_vision_robots: List[VisionRobotData], - blue_vision_robots: List[VisionRobotData], - ) -> Tuple[Dict[int, Robot], Dict[int, Robot]]: - if game_frame.my_team_is_yellow: - old_yellow_robots = game_frame.friendly_robots.copy() - old_blue_robots = game_frame.enemy_robots.copy() - else: - old_yellow_robots = game_frame.enemy_robots.copy() - old_blue_robots = game_frame.friendly_robots.copy() - - new_yellow_robots = self._combine_single_team_positions( - old_yellow_robots, - yellow_vision_robots, - friendly=game_frame.my_team_is_yellow, - ) - new_blue_robots = self._combine_single_team_positions( - old_blue_robots, - blue_vision_robots, - friendly=not game_frame.my_team_is_yellow, - ) - - return new_yellow_robots, new_blue_robots - - -class CameraCombiner: - def combine_cameras(self, frames: List[RawVisionData]) -> VisionData: - # Now we have access to the game we can do more sophisticated things - # Such as ignoring outlier cameras etc - - ts = [] - # maps robot id to list of frames seen for that robot - yellow_captured = defaultdict(list) - blue_captured = defaultdict(list) - balls_captured = defaultdict(list) - - # Each frame is from a different camera - for frame_ind, frame in enumerate(frames): - for yr in frame.yellow_robots: - yellow_captured[yr.id].append(yr) - - for br in frame.blue_robots: - blue_captured[br.id].append(br) - - for b in frame.balls: - balls_captured[frame_ind].append(b) - ts.append(frame.ts) - - avg_yellows = list(map(self._avg_robots, yellow_captured.values())) - avg_blues = list(map(self._avg_robots, blue_captured.values())) - # Current strategy is just to take the most confident ball - balls = self._combine_balls_by_proximity(balls_captured) - - return VisionData(sum(ts) / len(ts), avg_yellows, avg_blues, balls) - - def _avg_robots(self, rs: List[RawRobotData]) -> Optional[VisionRobotData]: - # All these robots should have the same id - if not rs: - return None - base_id = rs[0].id - tx, ty, tc = 0, 0, 0 - - sum_orientation_x_component = 0.0 - sum_orientation_y_component = 0.0 - for r in rs: - assert base_id == r.id - tx += r.x - ty += r.y - sum_orientation_x_component += np.cos(r.orientation) - sum_orientation_y_component += np.sin(r.orientation) - tc += r.confidence - - avg_orientation_x = sum_orientation_x_component / len(rs) - avg_orientation_y = sum_orientation_y_component / len(rs) - avg_orientation = np.atan2(avg_orientation_y, avg_orientation_x) - - return VisionRobotData(base_id, tx / len(rs), ty / len(rs), avg_orientation) - - def _combine_balls_by_proximity(self, bs: Dict[int, List[RawBallData]]) -> List[VisionBallData]: - combined_balls: List[VisionBallData] = [] - for ball_list in bs.values(): - for b in ball_list: - found = False - for i, cb in enumerate(combined_balls): - if CameraCombiner.ball_merge_predicate(b, cb): - found = True - combined_balls[i] = CameraCombiner.ball_merge(cb, b) - break - - if not found: - # If no ball close enough, must have found a new separate ball - combined_balls.append(b) - return combined_balls - - def ball_merge_predicate(b1: RawBallData, b2: RawBallData) -> bool: - return abs(b1.x - b2.x) + abs(b1.y - b2.y) < BALL_MERGE_THRESHOLD - - def ball_merge(b1: RawBallData, b2: RawBallData) -> RawBallData: - nx = (b1.x + b2.x) / 2 - ny = (b1.y + b2.y) / 2 - nz = (b1.z + b2.z) / 2 - nc = max(b1.confidence, b2.confidence) - return RawBallData(nx, ny, nz, nc) +from collections import defaultdict +from dataclasses import replace +from functools import partial +from typing import Dict, List, Optional, Tuple + +import numpy as np + +from utama_core.config.settings import BALL_MERGE_THRESHOLD +from utama_core.entities.data.raw_vision import RawBallData, RawRobotData, RawVisionData +from utama_core.entities.data.vector import Vector2D, Vector3D +from utama_core.entities.data.vision import VisionBallData, VisionData, VisionRobotData +from utama_core.entities.game import Ball, FieldBounds, GameFrame, Robot +from utama_core.global_utils.mapping_utils import map_friendly_enemy_to_colors +from utama_core.run.refiners.base_refiner import BaseRefiner +from utama_core.run.refiners.kalman import KalmanFilter, KalmanFilterBall + + +class AngleSmoother: + def __init__(self, alpha=0.3): + self.alpha = alpha # Smoothing factor for angle + self.smoothed_angles = {} # Stores last smoothed angle for each robot + + def smooth(self, old_angle: float, new_angle: float) -> float: + # Compute the shortest angular difference + diff = np.atan2(np.sin(new_angle - old_angle), np.cos(new_angle - old_angle)) + smoothed_angle = old_angle + self.alpha * diff + + return smoothed_angle + + +class PositionRefiner(BaseRefiner): + def __init__( + self, + field_bounds: FieldBounds, + bounds_buffer: float = 1.0, + filtering: bool = True, + ): + # alpha=0 means no change in angle (inf smoothing), alpha=1 means no smoothing + self.angle_smoother = AngleSmoother(alpha=1) + self.x_min = field_bounds.top_left[0] - bounds_buffer # expand left + self.x_max = field_bounds.bottom_right[0] + bounds_buffer # expand right + self.y_min = field_bounds.bottom_right[1] - bounds_buffer # expand bottom + self.y_max = field_bounds.top_left[1] + bounds_buffer # expand top + self.BOUNDS_BUFFER = bounds_buffer + + # For Kalman filtering and imputing vanished values. + self.filtering = filtering + self._filter_running = ( + False # Only start filtering once we have valid data to filter (i.e. after the first valid game frame) + ) + + if self.filtering: + # Instantiate a dedicated Kalman filter for each robot so filtering can be kept independent. + self.kalman_filters_yellow: dict[int, KalmanFilter] = {} + self.kalman_filters_blue: dict[int, KalmanFilter] = {} + self.kalman_filter_ball = KalmanFilterBall() + + # Primary function for the Refiner interface + def refine(self, game_frame: GameFrame, data: List[RawVisionData]) -> GameFrame: + frames = [frame for frame in data if frame is not None] + + # If no information just return the original + if not frames: + return game_frame + + # class VisionData: ts: float; yellow_robots: List[VisionRobotData]; blue_robots: List[VisionRobotData]; balls: List[VisionBallData] + # class VisionRobotData: id: int; x: float; y: float; orientation: float + combined_vision_data: VisionData = CameraCombiner().combine_cameras(frames) + + time_elapsed = combined_vision_data.ts - game_frame.ts + + # For filtering and vanishing + if self.filtering and self._filter_running: # Checks if the first valid game frame has been received. + # For vanishing: imputes combined_vision_data with null vision frames in place. + vision_yellow, vision_blue = self._include_vanished_robots(combined_vision_data, game_frame) + + yellow_rbt_last_frame, blue_rbt_last_frame = map_friendly_enemy_to_colors( + game_frame.my_team_is_yellow, + game_frame.friendly_robots, + game_frame.enemy_robots, + ) + + filtered_yellow_robots = [] + for y_rbt_id, vision_y_rbt in vision_yellow.items(): + if y_rbt_id not in self.kalman_filters_yellow: + self.kalman_filters_yellow[y_rbt_id] = KalmanFilter(id=y_rbt_id) + + filtered_robot = self.kalman_filters_yellow[y_rbt_id].filter_data( + vision_y_rbt, # new measurement + yellow_rbt_last_frame[y_rbt_id], # last frame + time_elapsed, + ) + + filtered_yellow_robots.append(filtered_robot) + + filtered_blue_robots = [] + for b_rbt_id, vision_b_rbt in vision_blue.items(): + if b_rbt_id not in self.kalman_filters_blue: + self.kalman_filters_blue[b_rbt_id] = KalmanFilter(id=b_rbt_id) + + filtered_robot = self.kalman_filters_blue[b_rbt_id].filter_data( + vision_b_rbt, # new measurement + blue_rbt_last_frame[b_rbt_id], # last frame + time_elapsed, + ) + + filtered_blue_robots.append(filtered_robot) + + combined_vision_data = VisionData( + ts=combined_vision_data.ts, + yellow_robots=filtered_yellow_robots, + blue_robots=filtered_blue_robots, + balls=combined_vision_data.balls, + ) + + # Some processing of robot vision data + new_yellow_robots, new_blue_robots = self._combine_both_teams_game_vision_positions( + game_frame, + combined_vision_data.yellow_robots, + combined_vision_data.blue_robots, + ) + + # After the balls have been combined, take the most confident + new_ball: Ball = PositionRefiner._get_most_confident_ball(combined_vision_data.balls) + + # For filtering and vanishing + if self.filtering and self._filter_running: + new_ball = self.kalman_filter_ball.filter_data( + new_ball, + game_frame.ball, + time_elapsed, + ) + elif new_ball is None: + # If none, take the ball from the last frame of the game + new_ball = game_frame.ball + + if game_frame.my_team_is_yellow: + new_game_frame = replace( + game_frame, + ts=combined_vision_data.ts, + friendly_robots=new_yellow_robots, + enemy_robots=new_blue_robots, + ball=new_ball, + ) + else: + new_game_frame = replace( + game_frame, + ts=combined_vision_data.ts, + friendly_robots=new_blue_robots, + enemy_robots=new_yellow_robots, + ball=new_ball, + ) + + return new_game_frame + + def reset(self): + """ + Resets the internal state of the refiner, including Kalman filters and vanishing trackers. + Should be called at the start of each game to ensure no leakage of information between games. + """ + self._filter_running = False + if self.filtering: + self.kalman_filters_yellow = {} + self.kalman_filters_blue = {} + self.kalman_filter_ball = KalmanFilterBall() + + def start_filtering(self): + """ + Start filtering after first valid frame is received from GameGater. + """ + self._filter_running = True + + def _include_vanished_robots( + self, vision_data: VisionData, game_frame: GameFrame + ) -> Tuple[dict[int, Optional[VisionRobotData]], dict[int, Optional[VisionRobotData]]]: + """ + Augment the VisionData lists with None for vanished robots so that the Kalman filter + knows that data vanished. + + Returns: + Tuple of (yellow_vision_dict, blue_vision_dict) where vanished robots are represented as None. + """ + + # TODO: major issue is that if we do a robot substitution, the + # Kalman filter will think the old robot vanished and a new robot appeared. + # needs to be adjusted when referee system is in place. + # see issue #107 on GitHub for more details. + + yellow_ids_last_frame, blue_ids_last_frame = map_friendly_enemy_to_colors( + game_frame.my_team_is_yellow, + game_frame.friendly_robots.keys(), + game_frame.enemy_robots.keys(), + ) + + # Current vision IDs + yellow_present = {r.id for r in vision_data.yellow_robots} + blue_present = {r.id for r in vision_data.blue_robots} + + # Start with current measurements + yellow_vision_dict: dict[int, Optional[VisionRobotData]] = {r.id: r for r in vision_data.yellow_robots} + blue_vision_dict: dict[int, Optional[VisionRobotData]] = {r.id: r for r in vision_data.blue_robots} + + # Add None for vanished robots + for robot_id in yellow_ids_last_frame - yellow_present: + yellow_vision_dict[robot_id] = None + for robot_id in blue_ids_last_frame - blue_present: + blue_vision_dict[robot_id] = None + + return yellow_vision_dict, blue_vision_dict + + # Static methods + @staticmethod + def _combine_robot_vision_data( + old_robot: Robot, robot_data: VisionRobotData, angle_smoother: AngleSmoother + ) -> Robot: + assert old_robot.id == robot_data.id + new_x, new_y = robot_data.x, robot_data.y + + # Needs fixing the bounds are off oren becoming -3.9rad + # # Smoothing + # new_orientation = angle_smoother.smooth( + # old_robot.orientation, robot_data.orientation + # ) + return replace( + old_robot, + id=robot_data.id, + p=Vector2D(new_x, new_y), + orientation=robot_data.orientation, + ) + + # Used at start of the game so assume robot does not have the ball + # Also assume velocity and acceleration are zero + @staticmethod + def _robot_from_vision(robot_data: VisionRobotData, is_friendly: bool) -> Robot: + return Robot( + id=robot_data.id, + is_friendly=is_friendly, + has_ball=False, + p=Vector2D(robot_data.x, robot_data.y), + v=Vector2D(0, 0), + a=Vector2D(0, 0), + orientation=robot_data.orientation, + ) + + @staticmethod + def _ball_from_vision(ball_data: VisionBallData) -> Ball: + zv = Vector3D(0, 0, 0) + return Ball(Vector3D(ball_data.x, ball_data.y, ball_data.z), zv, zv) + + @staticmethod + def _get_most_confident_ball(balls: List[VisionBallData]) -> Ball: + balls_by_confidence = sorted(balls, key=lambda ball: ball.confidence, reverse=True) + if not balls_by_confidence: + return None + return PositionRefiner._ball_from_vision(balls_by_confidence[0]) + + def _combine_single_team_positions( + self, + new_game_robots: Dict[int, Robot], + vision_robots: List[VisionRobotData], + friendly: bool, + ) -> Dict[int, Robot]: + for robot in vision_robots: + new_x, new_y = robot.x, robot.y + + if not (self.x_min <= new_x <= self.x_max and self.y_min <= new_y <= self.y_max): + # Out of bounds so ignore this robot + continue + + if robot.id not in new_game_robots: + # At the start of the game, we haven't seen anything yet, so just create a new robot + new_game_robots[robot.id] = PositionRefiner._robot_from_vision(robot, is_friendly=friendly) + else: + # Update with smoothed data. + new_game_robots[robot.id] = PositionRefiner._combine_robot_vision_data( + new_game_robots[robot.id], robot, self.angle_smoother + ) + return new_game_robots + + def _combine_both_teams_game_vision_positions( + self, + game_frame: GameFrame, + yellow_vision_robots: List[VisionRobotData], + blue_vision_robots: List[VisionRobotData], + ) -> Tuple[Dict[int, Robot], Dict[int, Robot]]: + if game_frame.my_team_is_yellow: + old_yellow_robots = game_frame.friendly_robots.copy() + old_blue_robots = game_frame.enemy_robots.copy() + else: + old_yellow_robots = game_frame.enemy_robots.copy() + old_blue_robots = game_frame.friendly_robots.copy() + + new_yellow_robots = self._combine_single_team_positions( + old_yellow_robots, + yellow_vision_robots, + friendly=game_frame.my_team_is_yellow, + ) + new_blue_robots = self._combine_single_team_positions( + old_blue_robots, + blue_vision_robots, + friendly=not game_frame.my_team_is_yellow, + ) + + return new_yellow_robots, new_blue_robots + + @property + def filter_running(self) -> bool: + return self._filter_running + + +class CameraCombiner: + def combine_cameras(self, frames: List[RawVisionData]) -> VisionData: + # Now we have access to the game we can do more sophisticated things + # Such as ignoring outlier cameras etc + + ts = [] + # maps robot id to list of frames seen for that robot + yellow_captured = defaultdict(list) + blue_captured = defaultdict(list) + balls_captured = defaultdict(list) + + # Each frame is from a different camera + for frame_ind, frame in enumerate(frames): + for yr in frame.yellow_robots: + yellow_captured[yr.id].append(yr) + + for br in frame.blue_robots: + blue_captured[br.id].append(br) + + for b in frame.balls: + balls_captured[frame_ind].append(b) + ts.append(frame.ts) + + avg_yellows = list(map(self._avg_robots, yellow_captured.values())) + avg_blues = list(map(self._avg_robots, blue_captured.values())) + # Current strategy is just to take the most confident ball + balls = self._combine_balls_by_proximity(balls_captured) + + return VisionData(sum(ts) / len(ts), avg_yellows, avg_blues, balls) + + def _avg_robots(self, rs: List[RawRobotData]) -> Optional[VisionRobotData]: + # All these robots should have the same id + if not rs: + return None + base_id = rs[0].id + tx, ty, tc = 0, 0, 0 + + sum_orientation_x_component = 0.0 + sum_orientation_y_component = 0.0 + for r in rs: + assert base_id == r.id + tx += r.x + ty += r.y + sum_orientation_x_component += np.cos(r.orientation) + sum_orientation_y_component += np.sin(r.orientation) + tc += r.confidence + + avg_orientation_x = sum_orientation_x_component / len(rs) + avg_orientation_y = sum_orientation_y_component / len(rs) + avg_orientation = np.atan2(avg_orientation_y, avg_orientation_x) + + return VisionRobotData(base_id, tx / len(rs), ty / len(rs), avg_orientation) + + def _combine_balls_by_proximity(self, bs: Dict[int, List[RawBallData]]) -> List[VisionBallData]: + combined_balls: List[VisionBallData] = [] + for ball_list in bs.values(): + for b in ball_list: + found = False + for i, cb in enumerate(combined_balls): + if CameraCombiner.ball_merge_predicate(b, cb): + found = True + combined_balls[i] = CameraCombiner.ball_merge(cb, b) + break + + if not found: + # If no ball close enough, must have found a new separate ball + combined_balls.append(b) + return combined_balls + + @staticmethod + def ball_merge_predicate(b1: RawBallData, b2: RawBallData) -> bool: + return abs(b1.x - b2.x) + abs(b1.y - b2.y) < BALL_MERGE_THRESHOLD + + @staticmethod + def ball_merge(b1: RawBallData, b2: RawBallData) -> RawBallData: + nx = (b1.x + b2.x) / 2 + ny = (b1.y + b2.y) / 2 + nz = (b1.z + b2.z) / 2 + nc = max(b1.confidence, b2.confidence) + return RawBallData(nx, ny, nz, nc) diff --git a/utama_core/run/strategy_runner.py b/utama_core/run/strategy_runner.py index fe6b73a5..fb27428b 100644 --- a/utama_core/run/strategy_runner.py +++ b/utama_core/run/strategy_runner.py @@ -82,6 +82,7 @@ class StrategyRunner: Defaults to 0 for each. rsim_vanishing (float, optional): When running in rsim, cause robots and ball to vanish with the given probability. Defaults to 0. + filtering (bool, optional): Turn on Kalman filtering. Defaults to true. """ def __init__( @@ -100,7 +101,8 @@ def __init__( print_real_fps: bool = False, # Turn this on for RSim profiler_name: Optional[str] = None, rsim_noise: RsimGaussianNoise = RsimGaussianNoise(), - rsim_vanishing: float = 0 + rsim_vanishing: float = 0, + filtering: bool = True, ): self.logger = logging.getLogger(__name__) @@ -129,9 +131,26 @@ def __init__( self._load_robot_controllers() assert_valid_bounding_box(self.field_bounds) - self.position_refiner = PositionRefiner(self.field_bounds) - self.velocity_refiner = VelocityRefiner() - self.robot_info_refiner = RobotInfoRefiner() + + ( + self.my_position_refiner, + self.my_velocity_refiner, + self.my_robot_info_refiner, + ) = self._init_refiners( + field_bounds, + filtering, + ) + + if self.opp_strategy: + ( + self.opp_position_refiner, + self.opp_velocity_refiner, + self.opp_robot_info_refiner, + ) = self._init_refiners( + field_bounds, + filtering, + ) + # self.referee_refiner = RefereeRefiner() ( self.my_game_history, @@ -224,14 +243,12 @@ def start_threads(self, vision_receiver: VisionReceiver): # , referee_receiver) # referee_thread.start() def _load_sim( - self, - rsim_noise: RsimGaussianNoise, - rsim_vanishing: float + self, rsim_noise: RsimGaussianNoise, rsim_vanishing: float ) -> Tuple[Optional[SSLStandardEnv], Optional[AbstractSimController]]: """Mode RSIM: Loads the RSim environment with the expected number of robots and corresponding sim controller. Mode GRSIM: Loads corresponding sim controller and teleports robots in GRSim to ensure the expected number of robots is met. - + Args: rsim_noise (RsimGaussianNoise, optional): When running in rsim, add Gaussian noise to balls and robots with the given standard deviation. The 3 parameters are for x (in m), y (in m), and orientation (in degrees) respectively. @@ -245,7 +262,13 @@ def _load_sim( """ if self.mode == Mode.RSIM: n_yellow, n_blue = map_friendly_enemy_to_colors(self.my_team_is_yellow, self.exp_friendly, self.exp_enemy) - rsim_env = SSLStandardEnv(n_robots_yellow=n_yellow, n_robots_blue=n_blue, render_mode=None, gaussian_noise=rsim_noise, vanishing=rsim_vanishing) + rsim_env = SSLStandardEnv( + n_robots_yellow=n_yellow, + n_robots_blue=n_blue, + render_mode=None, + gaussian_noise=rsim_noise, + vanishing=rsim_vanishing, + ) if self.opp_strategy: self.opp_strategy.load_rsim_env(rsim_env) @@ -386,6 +409,28 @@ def _load_robot_controllers(self): self.opp_strategy.load_robot_controller(opp_robot_controller) self.opp_strategy.load_motion_controller(self.opp_motion_controller(self.mode, self.rsim_env)) + def _init_refiners( + self, + field_bounds: FieldBounds, + filtering: bool, + ) -> tuple[PositionRefiner, VelocityRefiner, RobotInfoRefiner]: + """ + Initialize the position, velocity, and robot info refiners. + Args: + field_bounds (FieldBounds): The bounds of the field. + filtering (bool): Whether to use filtering in the position refiner. + Returns: + tuple: The initialized PositionRefiner, VelocityRefiner, and RobotInfoRefiner. + """ + position_refiner = PositionRefiner( + field_bounds, + filtering=filtering, + ) + velocity_refiner = VelocityRefiner() + robot_info_refiner = RobotInfoRefiner() + + return position_refiner, velocity_refiner, robot_info_refiner + def _load_game(self): """ Load the game state for both friendly and opponent strategies after waiting for valid game data with GameGater. @@ -398,10 +443,15 @@ def _load_game(self): self.exp_friendly, self.exp_enemy, self.vision_buffers, - self.position_refiner, + self.my_position_refiner, is_pvp=self.opp_strategy is not None, rsim_env=self.rsim_env, ) + + self.my_position_refiner.start_filtering() + if self.opp_strategy: + self.opp_position_refiner.start_filtering() + my_field = Field(self.my_team_is_right, self.field_bounds) my_game_history = GameHistory(MAX_GAME_HISTORY) my_game = Game(my_game_history, my_current_game_frame, field=my_field) @@ -435,6 +485,9 @@ def _reset_game(self): """ _ = self.my_strategy.robot_controller.get_robots_responses() + self.my_position_refiner.reset() + if self.opp_strategy: + self.opp_position_refiner.reset() ( self.my_game_history, self.my_current_game_frame, @@ -676,19 +729,25 @@ def _step_game( current_game_frame = self.opp_current_game_frame game_history = self.opp_game_history game = self.opp_game + position_refiner = self.opp_position_refiner + velocity_refiner = self.opp_velocity_refiner + robot_info_refiner = self.opp_robot_info_refiner else: strategy = self.my_strategy current_game_frame = self.my_current_game_frame game_history = self.my_game_history game = self.my_game + position_refiner = self.my_position_refiner + velocity_refiner = self.my_velocity_refiner + robot_info_refiner = self.my_robot_info_refiner # Pull responses from robot controller responses = strategy.robot_controller.get_robots_responses() # Update game frame with refined information - new_game_frame = self.position_refiner.refine(current_game_frame, vision_frames) - new_game_frame = self.velocity_refiner.refine(game_history, new_game_frame) # , robot_frame.imu_data) - new_game_frame = self.robot_info_refiner.refine(new_game_frame, responses) + new_game_frame = position_refiner.refine(current_game_frame, vision_frames) + new_game_frame = velocity_refiner.refine(game_history, new_game_frame) # , robot_frame.imu_data) + new_game_frame = robot_info_refiner.refine(new_game_frame, responses) # new_game_frame = self.referee_refiner.refine(new_game_frame, responses) # Store updated game frame @@ -703,16 +762,3 @@ def _step_game( game.add_game_frame(new_game_frame) strategy.step() - - -# if __name__ == "__main__": -# runner = StrategyRunner( -# strategy=RobotPlacementStrategy(id=3), -# my_team_is_yellow=True, -# my_team_is_right=True, -# mode="grsim", -# exp_friendly=6, -# exp_enemy=6, -# opp_strategy=RobotPlacementStrategy(id=3, invert=True), -# ) -# runner.run() diff --git a/utama_core/strategy/examples/__init__.py b/utama_core/strategy/examples/__init__.py index c97860c0..dffe12f6 100644 --- a/utama_core/strategy/examples/__init__.py +++ b/utama_core/strategy/examples/__init__.py @@ -5,3 +5,4 @@ ) from utama_core.strategy.examples.startup_strategy import StartupStrategy from utama_core.strategy.examples.two_robot_placement import TwoRobotPlacementStrategy +from utama_core.strategy.examples.point_cycle_strategy import PointCycleStrategy diff --git a/utama_core/strategy/examples/point_cycle_strategy.py b/utama_core/strategy/examples/point_cycle_strategy.py new file mode 100644 index 00000000..0b725616 --- /dev/null +++ b/utama_core/strategy/examples/point_cycle_strategy.py @@ -0,0 +1,182 @@ +"""Strategy for random movement within bounded area.""" + +from __future__ import annotations + +import random +from collections import deque +from typing import Optional, Tuple + +import py_trees + +from utama_core.entities.data.vector import Vector2D +from utama_core.entities.game.field import FieldBounds +from utama_core.skills.src.utils.move_utils import move +from utama_core.strategy.common.abstract_behaviour import AbstractBehaviour +from utama_core.strategy.common.abstract_strategy import AbstractStrategy + + +class PointCycleBehaviour(AbstractBehaviour): + """ + Behaviour that makes a robot move to randomly sampled targets within bounds. + + Args: + robot_id (int): The robot ID to control. + field_bounds (FieldBounds): ((min_x, max_x), (min_y, max_y)) bounds for movement. + endpoint_tolerance (float): Distance to consider target reached. + seed (Optional[int]): Seed for deterministic random sampling. + """ + + def __init__( + self, + robot_id: int, + field_bounds: FieldBounds, + endpoint_tolerance: float, + seed: Optional[int] = None, + ): + super().__init__(name=f"RandomPoint_{robot_id}") + self.robot_id = robot_id + self.field_bounds = field_bounds + self.endpoint_tolerance = endpoint_tolerance + + self.current_target = None + self.points = RandomPointSampler(field_bounds, seed=seed) + + def initialise(self): + """Initialize with a random target and speed.""" + # Will set target on first update when we have robot position + pass + + def update(self) -> py_trees.common.Status: + """Command robot to move to random targets.""" + game = self.blackboard.game + rsim_env = self.blackboard.rsim_env + + if not game.friendly_robots or self.robot_id not in game.friendly_robots: + return py_trees.common.Status.RUNNING + + robot = game.friendly_robots[self.robot_id] + robot_pos = Vector2D(robot.p.x, robot.p.y) + + # Generate initial target if needed + if self.current_target is None: + self.current_target = self.points.next_point + + # Check if target reached + distance_to_target = robot_pos.distance_to(self.current_target) + if distance_to_target <= self.endpoint_tolerance: + # Generate new target and speed + self.current_target = self.points.next_point + + # Visualize target + if rsim_env: + rsim_env.draw_point(self.current_target.x, self.current_target.y, color="green") + # Draw a line to show path + rsim_env.draw_line( + [ + (robot_pos.x, robot_pos.y), + (self.current_target.x, self.current_target.y), + ], + color="blue", + width=1, + ) + + # Generate movement command + cmd = move( + game, + self.blackboard.motion_controller, + self.robot_id, + self.current_target, + 0.0, # Face forward + ) + + self.blackboard.cmd_map[self.robot_id] = cmd + return py_trees.common.Status.RUNNING + + +class PointCycleStrategy(AbstractStrategy): + """ + Strategy that instantiates one PointCycleBehaviour per friendly robot + and executes them in parallel within specified field bounds. + + Args: + n_robots (int): Number of robots to control. + field_bounds (FieldBounds): Movement bounds. + endpoint_tolerance (float): Distance to consider target reached. + seed (Optional[int]): Base seed for deterministic behaviour. + """ + + def __init__( + self, + n_robots: int, + field_bounds: FieldBounds, + endpoint_tolerance: float, + seed: Optional[int] = None, + ): + self.n_robots = n_robots + self.field_bounds = field_bounds + self.endpoint_tolerance = endpoint_tolerance + self.seed = seed + super().__init__() + + def assert_exp_robots(self, n_runtime_friendly: int, n_runtime_enemy: int): + """Requires number of friendly robots to match.""" + return n_runtime_friendly >= self.n_robots + + def assert_exp_goals(self, includes_my_goal_line: bool, includes_opp_goal_line: bool): + return True + + def get_min_bounding_zone(self) -> Optional[FieldBounds]: + """Return the movement bounds.""" + return self.field_bounds + + def create_behaviour_tree(self) -> py_trees.behaviour.Behaviour: + """Create parallel behaviour tree with all robot random movement behaviours.""" + if self.n_robots == 1: + return PointCycleBehaviour( + robot_id=0, + field_bounds=self.field_bounds, + endpoint_tolerance=self.endpoint_tolerance, + seed=self.seed, + ) + + behaviours = [] + for robot_id in range(self.n_robots): + behaviour = PointCycleBehaviour( + robot_id=robot_id, + field_bounds=self.field_bounds, + endpoint_tolerance=self.endpoint_tolerance, + seed=None if self.seed is None else self.seed + robot_id, + ) + behaviours.append(behaviour) + + return py_trees.composites.Parallel( + name="RandomPoint", + policy=py_trees.common.ParallelPolicy.SuccessOnAll(), + children=behaviours, + ) + + +class RandomPointSampler: + """ + Uniform random point sampler within rectangular field bounds. + + Args: + field_bounds (FieldBounds): ((min_x, max_x), (min_y, max_y)) + seed (Optional[int]): Random seed for deterministic sampling. + """ + + def __init__(self, field_bounds: FieldBounds, seed: int = 42): + self.field_bounds = field_bounds + self.rng = random.Random(seed) + + @property + def next_point(self) -> Vector2D: + min_x = self.field_bounds.bottom_right[0] + max_x = self.field_bounds.top_left[0] + min_y = self.field_bounds.bottom_right[1] + max_y = self.field_bounds.top_left[1] + + x = self.rng.uniform(min_x, max_x) + y = self.rng.uniform(min_y, max_y) + + return Vector2D(x=x, y=y) diff --git a/utama_core/tests/entities/test_proximity_lookup.py b/utama_core/tests/entities/test_proximity_lookup.py index 3c5dd438..ff4a414c 100644 --- a/utama_core/tests/entities/test_proximity_lookup.py +++ b/utama_core/tests/entities/test_proximity_lookup.py @@ -1,10 +1,12 @@ import numpy as np +import pytest from utama_core.entities.data.vector import Vector2D from utama_core.entities.game.proximity_lookup import ProximityLookup from utama_core.entities.game.robot import Robot +@pytest.mark.filterwarnings("ignore:Invalid closest_to_ball query") # Ignore warning about no ball def test_proximity_lookup_handles_none_inputs(): lookup = ProximityLookup(friendly_robots=None, enemy_robots=None, ball=None) obj, dist = lookup.closest_to_ball() @@ -12,6 +14,7 @@ def test_proximity_lookup_handles_none_inputs(): assert np.isinf(dist) +@pytest.mark.filterwarnings("ignore:Invalid closest_to_ball query") # Ignore warning about no ball def test_proximity_lookup_with_no_ball(): robots = { 1: Robot( diff --git a/utama_core/tests/refiners/kalman_test.py b/utama_core/tests/refiners/kalman_test.py new file mode 100644 index 00000000..c0c742fb --- /dev/null +++ b/utama_core/tests/refiners/kalman_test.py @@ -0,0 +1,450 @@ +""" +Correctness tests for KalmanFilter and KalmanFilterBall. + +Key properties checked: +- Filtered output is a weighted blend of prediction and measurement. +- Vanished frames fall back to velocity-based prediction. +- Repeated identical measurements converge to the true value. +- Orientation wrapping is handled correctly near the ±π boundary. +- Return types and shapes are always correct. +""" + +import math + +import numpy as np +import pytest + +from utama_core.entities.data.vector import Vector2D, Vector3D +from utama_core.entities.data.vision import VisionRobotData +from utama_core.entities.game import Ball +from utama_core.entities.game.robot import Robot +from utama_core.run.refiners.kalman import KalmanFilter, KalmanFilterBall + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def make_robot( + x: float = 0.0, + y: float = 0.0, + vx: float = 0.0, + vy: float = 0.0, + orientation: float = 0.0, +) -> Robot: + return Robot( + id=0, + is_friendly=True, + has_ball=False, + p=Vector2D(x, y), + v=Vector2D(vx, vy), + a=Vector2D(0, 0), + orientation=orientation, + ) + + +def make_ball( + x: float = 0.0, + y: float = 0.0, + z: float = 0.0, + vx: float = 0.0, + vy: float = 0.0, + vz: float = 0.0, +) -> Ball: + return Ball( + p=Vector3D(x, y, z), + v=Vector3D(vx, vy, vz), + a=Vector3D(0, 0, 0), + ) + + +def make_vision(x: float | None, y: float | None, orientation: float | None, robot_id: int = 0) -> VisionRobotData: + return VisionRobotData(id=robot_id, x=x, y=y, orientation=orientation) + + +# --------------------------------------------------------------------------- +# KalmanFilter – construction guards +# --------------------------------------------------------------------------- + + +class TestKalmanFilterInit: + def test_default_construction(self): + kf = KalmanFilter() + assert kf.id == 0 + + def test_custom_id(self): + kf = KalmanFilter(id=3) + assert kf.id == 3 + + def test_zero_noise_xy_raises(self): + with pytest.raises(AssertionError): + KalmanFilter(noise_xy_sd=0) + + def test_negative_noise_xy_raises(self): + with pytest.raises(AssertionError): + KalmanFilter(noise_xy_sd=-0.5) + + def test_zero_noise_th_raises(self): + with pytest.raises(AssertionError): + KalmanFilter(noise_th_sd_deg=0) + + def test_negative_noise_th_raises(self): + with pytest.raises(AssertionError): + KalmanFilter(noise_th_sd_deg=-1) + + +# --------------------------------------------------------------------------- +# KalmanFilter – _step_xy +# --------------------------------------------------------------------------- + + +class TestKalmanFilterStepXY: + def _make_last_frame(self, robot: Robot) -> dict[int, Robot]: + return {robot.id: robot} + + def test_returns_tuple_of_two_floats(self): + kf = KalmanFilter() + robot = make_robot(x=1.0, y=2.0) + result = kf._step_xy((1.0, 2.0), robot, time_elapsed=0.1) + assert isinstance(result, tuple) and len(result) == 2 + + def test_initialises_state_on_first_call(self): + kf = KalmanFilter() + assert kf.state_xy is None + robot = make_robot(x=3.0, y=4.0) + kf._step_xy((3.0, 4.0), robot, time_elapsed=0.1) + assert kf.state_xy is not None + + def test_exact_repeated_measurement_converges(self): + """After many steps with zero velocity and the same measurement the filter should + converge very close to the true position.""" + kf = KalmanFilter(noise_xy_sd=0.01) + robot = make_robot(x=2.0, y=5.0) + for _ in range(50): + result = kf._step_xy((2.0, 5.0), robot, time_elapsed=0.1) + assert abs(result[0] - 2.0) < 1e-3 + assert abs(result[1] - 5.0) < 1e-3 + + def test_output_between_prediction_and_measurement(self): + """When prediction and measurement differ, filtered output must lie strictly + between them (weighted blend).""" + kf = KalmanFilter() + robot = make_robot(x=0.0, y=0.0) + # Initialise filter state + kf._step_xy((0.0, 0.0), robot, time_elapsed=0.1) + + # Now send a measurement far from the prediction + robot_stationary = make_robot(x=0.0, y=0.0, vx=0.0, vy=0.0) + result = kf._step_xy((3.0, 3.0), robot_stationary, time_elapsed=0.1) + # Should be pulled toward measurement but not all the way + assert 0.0 < result[0] < 3.0 + 1e-9 + assert 0.0 < result[1] < 3.0 + 1e-9 + + def test_vanished_frame_uses_velocity_prediction(self): + """Consecutive vanished steps must each advance position by exactly v * dt.""" + kf = KalmanFilter() + vx, vy = 1.0, 0.5 + robot = make_robot(x=0.0, y=0.0, vx=vx, vy=vy) + kf._step_xy(None, robot, time_elapsed=0.1) # init (no Kalman update) + + dt = 0.1 + result1 = kf._step_xy(None, robot, time_elapsed=dt) + result2 = kf._step_xy(None, robot, time_elapsed=dt) + # Each vanished step should advance by v * dt + assert abs((result2[0] - result1[0]) - vx * dt) < 1e-6 + assert abs((result2[1] - result1[1]) - vy * dt) < 1e-6 + + def test_state_advances_with_velocity_over_multiple_vanished_steps(self): + kf = KalmanFilter() + vx = 2.0 + robot = make_robot(x=0.0, y=0.0, vx=vx, vy=0.0) + kf._step_xy((0.0, 0.0), robot, time_elapsed=0.1) + + dt = 0.1 + steps = 5 + for _ in range(steps): + result = kf._step_xy(None, robot, time_elapsed=dt) + + # After n vanished steps starting from 0 the position grows monotonically + assert result[0] > 0.0 + + +# --------------------------------------------------------------------------- +# KalmanFilter – _step_th +# --------------------------------------------------------------------------- + + +class TestKalmanFilterStepTH: + def test_returns_float(self): + kf = KalmanFilter() + result = kf._step_th(0.5, last_th=0.0) + assert isinstance(result, float) + + def test_initialises_state_on_first_call(self): + kf = KalmanFilter() + assert kf.state_th is None + kf._step_th(1.0, last_th=1.0) + assert kf.state_th is not None + + def test_exact_repeated_measurement_converges(self): + kf = KalmanFilter(noise_th_sd_deg=5) + th = math.pi / 4 + for _ in range(50): + result = kf._step_th(th, last_th=th) + assert abs(result - th) < 1e-3 + + def test_vanished_frame_preserves_state(self): + kf = KalmanFilter() + kf._step_th(1.0, last_th=1.0) # init + state_before = kf.state_th + kf._step_th(None, last_th=1.0) + assert kf.state_th == state_before + + def test_output_wrapped_to_minus_pi_plus_pi(self): + kf = KalmanFilter() + # Initialise near +π + kf._step_th(math.pi - 0.1, last_th=math.pi - 0.1) + # Measurement just past +π (wraps to ≈ -π) + result = kf._step_th(-math.pi + 0.1, last_th=math.pi) + assert -math.pi <= result <= math.pi + + def test_circular_average_across_pi_boundary(self): + """Averaging π-0.1 and -π+0.1 should stay near ±π, not collapse to 0.""" + kf = KalmanFilter() + th1 = math.pi - 0.1 + th2 = -math.pi + 0.1 + kf._step_th(th1, last_th=th1) + result = kf._step_th(th2, last_th=th1) + # Result must be close to ±π, not near 0 + assert abs(result) > math.pi / 2 + + +# --------------------------------------------------------------------------- +# KalmanFilter – filter_data (public API) +# --------------------------------------------------------------------------- + + +class TestKalmanFilterFilterData: + def _last_frame(self, robot: Robot) -> dict[int, Robot]: + return {robot.id: robot} + + def test_returns_vision_robot_data(self): + kf = KalmanFilter() + robot = make_robot() + result = kf.filter_data(make_vision(1.0, 2.0, 0.5), self._last_frame(robot)[robot.id], 0.1) + assert isinstance(result, VisionRobotData) + + def test_id_preserved(self): + kf = KalmanFilter(id=2) + robot = Robot( + id=2, + is_friendly=True, + has_ball=False, + p=Vector2D(0, 0), + v=Vector2D(0, 0), + a=Vector2D(0, 0), + orientation=0.0, + ) + result = kf.filter_data(make_vision(1.0, 2.0, 0.3, robot_id=2), robot, 0.1) + assert result.id == 2 + + def test_valid_data_returns_finite_values(self): + kf = KalmanFilter() + robot = make_robot(x=0.0, y=0.0) + result = kf.filter_data(make_vision(1.0, 1.0, 0.2), self._last_frame(robot)[robot.id], 0.1) + assert math.isfinite(result.x) + assert math.isfinite(result.y) + assert math.isfinite(result.orientation) + + def test_vanished_data_returns_finite_values(self): + kf = KalmanFilter() + robot = make_robot(x=1.0, y=1.0) + # First call to initialise + kf.filter_data(make_vision(1.0, 1.0, 0.0), self._last_frame(robot)[robot.id], 0.1) + # Second call with vanished data + result = kf.filter_data(None, self._last_frame(robot)[robot.id], 0.1) + assert math.isfinite(result.x) + assert math.isfinite(result.y) + assert math.isfinite(result.orientation) + + def test_convergence_with_repeated_measurement(self): + kf = KalmanFilter() + robot = make_robot(x=5.0, y=3.0) + for _ in range(50): + result = kf.filter_data(make_vision(5.0, 3.0, 1.0), self._last_frame(robot)[robot.id], 0.1) + assert abs(result.x - 5.0) < 1e-3 + assert abs(result.y - 3.0) < 1e-3 + assert abs(result.orientation - 1.0) < 1e-2 + + +# --------------------------------------------------------------------------- +# KalmanFilterBall – construction guards +# --------------------------------------------------------------------------- + + +class TestKalmanFilterBallInit: + def test_default_construction(self): + kf = KalmanFilterBall() + assert kf.state is None + + def test_zero_noise_raises(self): + with pytest.raises(AssertionError): + KalmanFilterBall(noise_sd=0) + + def test_negative_noise_raises(self): + with pytest.raises(AssertionError): + KalmanFilterBall(noise_sd=-1) + + +# --------------------------------------------------------------------------- +# KalmanFilterBall – _step +# --------------------------------------------------------------------------- + + +class TestKalmanFilterBallStep: + def test_returns_tuple_of_three_floats(self): + kf = KalmanFilterBall() + ball = make_ball() + result = kf._step((0.0, 0.0, 0.0), ball, time_elapsed=0.1) + assert isinstance(result, tuple) and len(result) == 3 + + def test_initialises_state_on_first_call(self): + kf = KalmanFilterBall() + assert kf.state is None + kf._step((1.0, 2.0, 0.0), make_ball(1.0, 2.0), time_elapsed=0.1) + assert kf.state is not None + + def test_exact_repeated_measurement_converges(self): + kf = KalmanFilterBall(noise_sd=0.01) + ball = make_ball(x=1.0, y=-2.0, z=0.0) + for _ in range(50): + result = kf._step((1.0, -2.0, 0.0), ball, time_elapsed=0.1) + assert abs(result[0] - 1.0) < 1e-3 + assert abs(result[1] - (-2.0)) < 1e-3 + assert abs(result[2] - 0.0) < 1e-3 + + def test_vanished_frame_uses_velocity_prediction(self): + """Consecutive vanished steps must each advance position by exactly v * dt.""" + kf = KalmanFilterBall() + vx, vy, vz = 1.0, 2.0, 0.5 + ball = make_ball(x=0.0, y=0.0, z=0.0, vx=vx, vy=vy, vz=vz) + kf._step(None, ball, time_elapsed=0.1) # init (no Kalman update) + + dt = 0.1 + result1 = kf._step(None, ball, time_elapsed=dt) + result2 = kf._step(None, ball, time_elapsed=dt) + # Each vanished step should advance by v * dt + assert abs((result2[0] - result1[0]) - vx * dt) < 1e-6 + assert abs((result2[1] - result1[1]) - vy * dt) < 1e-6 + assert abs((result2[2] - result1[2]) - vz * dt) < 1e-6 + + def test_output_between_prediction_and_measurement(self): + kf = KalmanFilterBall() + ball = make_ball() + kf._step((0.0, 0.0, 0.0), ball, time_elapsed=0.1) + + stationary_ball = make_ball(x=0.0, y=0.0, z=0.0) + result = kf._step((4.0, 4.0, 1.0), stationary_ball, time_elapsed=0.1) + assert 0.0 < result[0] < 4.0 + 1e-9 + assert 0.0 < result[1] < 4.0 + 1e-9 + + +# --------------------------------------------------------------------------- +# KalmanFilterBall – filter_data (public API) +# --------------------------------------------------------------------------- + + +class TestKalmanFilterBallFilterData: + def test_returns_ball(self): + kf = KalmanFilterBall() + ball = make_ball(1.0, 2.0, 0.0) + result = kf.filter_data(ball, ball, time_elapsed=0.1) + assert isinstance(result, Ball) + + def test_valid_data_returns_finite_position(self): + kf = KalmanFilterBall() + ball = make_ball(1.0, 2.0, 0.0) + result = kf.filter_data(ball, ball, time_elapsed=0.1) + assert math.isfinite(result.p.x) + assert math.isfinite(result.p.y) + assert math.isfinite(result.p.z) + + def test_none_data_returns_finite_position(self): + """A None ball (not detected) should produce a predicted ball, not crash.""" + kf = KalmanFilterBall() + last = make_ball(1.0, 1.0, 0.0) + kf.filter_data(last, last, time_elapsed=0.1) # init + result = kf.filter_data(None, last, time_elapsed=0.1) + assert isinstance(result, Ball) + assert math.isfinite(result.p.x) + assert math.isfinite(result.p.y) + assert math.isfinite(result.p.z) + + def test_none_data_velocity_zeroed(self): + """When the ball has vanished, velocity is set to zero in the returned Ball.""" + kf = KalmanFilterBall() + last = make_ball(0.0, 0.0, 0.0) + kf.filter_data(last, last, time_elapsed=0.1) + result = kf.filter_data(None, last, time_elapsed=0.1) + assert result.v.x == 0.0 + assert result.v.y == 0.0 + assert result.v.z == 0.0 + + def test_velocity_passed_through_from_measurement(self): + """Velocity from a valid Ball measurement should be passed through unchanged.""" + kf = KalmanFilterBall() + ball = make_ball(1.0, 2.0, 0.0, vx=3.0, vy=4.0, vz=0.5) + result = kf.filter_data(ball, ball, time_elapsed=0.1) + assert result.v.x == 3.0 + assert result.v.y == 4.0 + assert result.v.z == 0.5 + + def test_convergence_with_repeated_measurement(self): + kf = KalmanFilterBall(noise_sd=0.01) + ball = make_ball(x=3.0, y=-1.0, z=0.0) + for _ in range(50): + result = kf.filter_data(ball, ball, time_elapsed=0.1) + assert abs(result.p.x - 3.0) < 1e-3 + assert abs(result.p.y - (-1.0)) < 1e-3 + assert abs(result.p.z - 0.0) < 1e-3 + + def test_prediction_tracks_moving_ball_after_vanish(self): + """After the ball vanishes, successive None steps should accumulate displacement.""" + kf = KalmanFilterBall() + vx = 1.0 + ball = make_ball(x=0.0, y=0.0, z=0.0, vx=vx) + kf.filter_data(ball, ball, time_elapsed=0.1) # init + + dt = 0.1 + steps = 5 + prev_x = 0.0 + for _ in range(steps): + result = kf.filter_data(None, ball, time_elapsed=dt) + assert result.p.x > prev_x + prev_x = result.p.x + + def test_ball_covariance_shrinks_with_repeated_measurement(self): + """After many identical measurements, the covariance should shrink (filter gains confidence).""" + kf = KalmanFilterBall(noise_sd=0.001) + ball = make_ball(x=1.0, y=2.0) + initial_cov = kf.covariance_mat.copy() + for _ in range(50): + kf._step((1.0, 2.0, 0.0), ball, 0.1) + + # Diagonal elements (variances) should shrink + assert np.all(np.diag(kf.covariance_mat) < np.diag(initial_cov)) + + def test_robot_xy_covariance_shrinks_with_repeated_measurement(self): + kf = KalmanFilter(id=1, noise_xy_sd=0.001, noise_th_sd_deg=5) + + robot = make_robot(x=1.0, y=2.0, orientation=0.0) + + # First call initializes state + kf._step_xy((1.0, 2.0), robot, time_elapsed=0.1) + + initial_cov = kf.covariance_mat_xy.copy() + + for _ in range(50): + kf._step_xy((1.0, 2.0), robot, time_elapsed=0.1) + + assert np.all(np.diag(kf.covariance_mat_xy) < np.diag(initial_cov))