From d1f79bc157fa629de67545e81336a776199f946e Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 00:28:52 +0000 Subject: [PATCH 01/15] chore: expand .gitignore for build, test, and report artifacts --- .gitignore | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/.gitignore b/.gitignore index a2c04a9..fcea072 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,41 @@ +# Python bytecode __pycache__/ **/__pycache__/ *.pyc + +# Build / packaging artifacts +build/ +dist/ +*.egg-info/ +*.egg +*.so +.eggs/ +wheelhouse/ + +# Test / coverage artifacts +.pytest_cache/ +.coverage +.coverage.* +htmlcov/ +coverage.xml +.cache/ + +# Environments / tooling +.pixi/ +.venv/ +venv/ +.env + +# Editor / OS cruft +.DS_Store +**/.DS_Store +.idea/ +.vscode/ + +# Renovation reports & scratch (uncommitted, human-facing) +RENOVATION_TODO.md +bug_report.md +potential_dead_code.md +documentation_report.md +*_report.md +.claude/context/ From d9d48e28de46dd1218ef2a6a703eff214efe5f20 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 00:30:43 +0000 Subject: [PATCH 02/15] chore: gitignore .claude working directory --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fcea072..9019848 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,6 @@ bug_report.md potential_dead_code.md documentation_report.md *_report.md -.claude/context/ + +# Claude working files (never committed, per user preference) +.claude/ From 115f0368a175dc2a6177d20d7b710ec972f2c9b6 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 00:34:11 +0000 Subject: [PATCH 03/15] chore: stop tracking .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Wed, 10 Jun 2026 00:37:31 +0000 Subject: [PATCH 04/15] build: add pixi dev environment and pytest conftest Reproducible dev env (python 3.11-3.13 features, numpy/pandas/scipy + pytest) with build/test/test-cov tasks. Root conftest.py puts the repo on sys.path so the flat module imports during the pre-packaging test phases. --- conftest.py | 7 + pixi.lock | 2659 +++++++++++++++++++++++++++++++++++++++++++++++++++ pixi.toml | 35 + 3 files changed, 2701 insertions(+) create mode 100644 conftest.py create mode 100644 pixi.lock create mode 100644 pixi.toml diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..927c977 --- /dev/null +++ b/conftest.py @@ -0,0 +1,7 @@ +"""Pytest configuration. + +The presence of this file at the repo root makes pytest add the repo root to +``sys.path``, so the top-level ``pybeh_pd`` / ``pybeh_copy`` modules import during +testing without an install. This is intentional for the pre-packaging phases; once +the package is installed (editable), the import resolves the same way. +""" diff --git a/pixi.lock b/pixi.lock new file mode 100644 index 0000000..88aef25 --- /dev/null +++ b/pixi.lock @@ -0,0 +1,2659 @@ +version: 7 +platforms: +- name: linux-64 +- name: osx-64 +- name: osx-arm64 +environments: + default: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py313h3dea7bd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py313hf6604e3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py313hbfd7664_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py313h035b7d0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py313hb870fc3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py313hfd25234_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.13-h3d5d122_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py313h65a2061_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py313hce9b930_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py313h1188861_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + py311: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.15-ha9537fe_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.15-h8561d8f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + py312: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py312h8a5da7c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py312h54fa4ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py312heb39f77_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py312h746d82c_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py312h8e27051_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.13-ha9537fe_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py312h04c11ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py312h6510ced_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.13-h8561d8f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + py313: + channels: + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py313h3dea7bd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py313hf6604e3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py313hbfd7664_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py313h035b7d0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py313hb870fc3_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py313hfd25234_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.13-h3d5d122_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py313h65a2061_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py313hce9b930_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py313h1188861_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + build_number: 20 + sha256: 1dd3fffd892081df9726d7eb7e0dea6198962ba775bd88842135a4ddb4deb3c9 + md5: a9f577daf3de00bca7c3c76c0ecbd1de + depends: + - __glibc >=2.17,<3.0.a0 + - libgomp >=7.5.0 + constrains: + - openmp_impl <0.0a0 + license: BSD-3-Clause + license_family: BSD + size: 28948 + timestamp: 1770939786096 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 + md5: d2ffd7602c02f2b316fd921d39876885 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + size: 260182 + timestamp: 1771350215188 +- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda + sha256: ebefe7c8a41d14e4a50c5b862cf0226b3ac745495415bb6fb0db364b945cfe3a + md5: f875c239f662e1b31fbf32282f1da087 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 399156 + timestamp: 1779838054673 +- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py312h8a5da7c_0.conda + sha256: 80b990c6870c721bcde5e14e71d3560bac3dad93b54d027f723dca2bb7ccda03 + md5: 6668e2af2de730400bdce9cf2ea132f9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 389696 + timestamp: 1779838017522 +- conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py313h3dea7bd_0.conda + sha256: b4ff99ffe4e60119c2f99fa29234b4267f7e0f43dbf5396dad0f8adaf95284e2 + md5: 86bbb569988f077e5cb30acac5799599 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 396489 + timestamp: 1779837909103 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c + md5: 18335a698559cdbcd86150a48bf54ba6 + depends: + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - binutils_impl_linux-64 2.45.1 + license: GPL-3.0-only + license_family: GPL + size: 728002 + timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda + build_number: 8 + sha256: b2da6bfd72a1c9cb143ccf64bf5b28790cb4eb58bd1cb978f6537b2322f7d48b + md5: 00fc660ab1b2f5ca07e92b4900d10c79 + depends: + - libopenblas >=0.3.33,<0.3.34.0a0 + - libopenblas >=0.3.33,<1.0a0 + constrains: + - blas 2.308 openblas + - mkl <2027 + - libcblas 3.11.0 8*_openblas + - liblapack 3.11.0 8*_openblas + - liblapacke 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 18804 + timestamp: 1779859100675 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda + build_number: 8 + sha256: 1a2bc77bb26520255904a3d9b1f40e6bf0bf9d8d3405c7709dd162282820915a + md5: 33a413f1095f8325e5c30fde3b0d2445 + depends: + - libblas 3.11.0 8_h4a7cf45_openblas + constrains: + - blas 2.308 openblas + - liblapacke 3.11.0 8*_openblas + - liblapack 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 18778 + timestamp: 1779859107964 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7 + md5: 93764a5ca80616e9c10106cdaec92f74 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + size: 77294 + timestamp: 1779278686680 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + sha256: 31f19b6a88ce40ebc0d5a992c131f57d919f73c0b92cd1617a5bec83f6e961e6 + md5: a360c33a5abe61c07959e449fa1453eb + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + size: 58592 + timestamp: 1769456073053 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + sha256: 8e0a3b5e41272e5678499b5dfc4cddb673f9e935de01eb0767ce857001229f46 + md5: 57736f29cc2b0ec0b6c2952d3f101b6a + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgcc-ng ==15.2.0=*_19 + - libgomp 15.2.0 he0feb66_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 1041084 + timestamp: 1778269013026 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + sha256: 9dcf54adfaa5e861123c2da4f2f0451a685464ea7e5a41ad91cf67b31d658d98 + md5: 331ee9b72b9dff570d56b1302c5ab37d + depends: + - libgcc 15.2.0 he0feb66_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 27694 + timestamp: 1778269016987 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + sha256: 561a42758ef25b9ce308c4e2cf56daee4f06138385a17e29a492cd928e00be6f + md5: 42bf7eca1a951735fa06c0e3c0d5c8e6 + depends: + - libgfortran5 15.2.0 h68bc16d_19 + constrains: + - libgfortran-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 27655 + timestamp: 1778269042954 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + sha256: 057978bb69fea29ed715a9b98adf71015c31baecc4aeb2bfc20d4fd5d83579d4 + md5: 85072b0ad177c966294f129b7c04a2d5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 2483673 + timestamp: 1778269025089 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + sha256: 5abe4ab9d93f6c9757d654f1969ae2267d4505315c1f2f8fe705fd60af084f1b + md5: faac990cb7aedc7f3a2224f2c9b0c26c + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 603817 + timestamp: 1778268942614 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda + build_number: 8 + sha256: 168e327d737059553e15cc6ec36d76b9bbb3931c2a7721555fd68b4c9348b247 + md5: 809be8ba8712c77bc7d44c2d99390dc4 + depends: + - libblas 3.11.0 8_h4a7cf45_openblas + constrains: + - blas 2.308 openblas + - libcblas 3.11.0 8*_openblas + - liblapacke 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 18790 + timestamp: 1779859115086 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + sha256: ec30e52a3c1bf7d0425380a189d209a52baa03f22fb66dd3eb587acaa765bd6d + md5: b88d90cad08e6bc8ad540cb310a761fb + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - xz 5.8.3.* + license: 0BSD + size: 113478 + timestamp: 1775825492909 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 + md5: 2c21e66f50753a083cbe6b80f38268fa + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-2-Clause + license_family: BSD + size: 92400 + timestamp: 1769482286018 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5 + md5: d864d34357c3b65a4b731f78c0801dc4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-only + license_family: GPL + size: 33731 + timestamp: 1750274110928 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + sha256: 3d9aa85648e5e18a6d66db98b8c4317cc426721ad7a220aa86330d1ccedc8903 + md5: 2d3278b721e40468295ca755c3b84070 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + constrains: + - openblas >=0.3.33,<0.3.34.0a0 + license: BSD-3-Clause + license_family: BSD + size: 5931919 + timestamp: 1776993658641 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + sha256: 1ab603b6ec93933e76027e1f23b21b22b858ba1b56f1e1695ef6fe5e80cb7358 + md5: 062b0ac602fb0adf250e3dfa86f221c4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libzlib >=1.3.2,<2.0a0 + license: blessing + size: 957849 + timestamp: 1780574429573 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc + md5: 5794b3bdc38177caf969dabd3af08549 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc 15.2.0 he0feb66_19 + constrains: + - libstdcxx-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 5852044 + timestamp: 1778269036376 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + sha256: 3f0edf1280e2f6684a986f821eaa3e123d2694a00b31b96ca0d4a4c12c129231 + md5: 7d0a66598195ef00b6efc55aefc7453b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + size: 40163 + timestamp: 1779118517630 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c + md5: 5aa797f8787fe7a17d1b0821485b5adc + depends: + - libgcc-ng >=12 + license: LGPL-2.1-or-later + size: 100393 + timestamp: 1702724383534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + sha256: 55044c403570f0dc26e6364de4dc5368e5f3fc7ff103e867c487e2b5ab2bcda9 + md5: d87ff7921124eccd67248aa483c23fec + depends: + - __glibc >=2.17,<3.0.a0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + size: 63629 + timestamp: 1774072609062 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + sha256: fc89f74bbe362fb29fa3c037697a89bec140b346a2469a90f7936d1d7ea4d8a3 + md5: fc21868a1a5aacc937e7a18747acb8a5 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: X11 AND BSD-3-Clause + size: 918956 + timestamp: 1777422145199 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda + sha256: 8e8fb64c1a51282e8940d57d116aec54a4d66da59594973ae9c0b35d419b9a81 + md5: 5d4e35d7097b88c8b1455ef9f6ddf511 + depends: + - python + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libstdcxx >=14 + - libblas >=3.9.0,<4.0a0 + - python_abi 3.11.* *_cp311 + - liblapack >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 9389525 + timestamp: 1779169198155 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda + sha256: dfcbeadb3e7ad0da7a55a0525884ca34c19584154e13cc4159396b305d1bd445 + md5: 6e31d55ee1110fda83b4f4045f4d73ff + depends: + - python + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + - python_abi 3.12.* *_cp312 + - libcblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 8759520 + timestamp: 1779169200325 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py313hf6604e3_0.conda + sha256: 3740c9bc562db9c6f252f8697c5c7948bb48784346856f6d6308aba72ea4f00b + md5: a5fdb80595ec7912e6b1634b2abd4b50 + depends: + - python + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libcblas >=3.9.0,<4.0a0 + - python_abi 3.13.* *_cp313 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 8864096 + timestamp: 1779169199037 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + sha256: c0ef482280e38c71a08ad6d71448194b719630345b0c9c60744a2010e8a8e0cb + md5: da1b85b6a87e141f5140bb9924cecab0 + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + size: 3167099 + timestamp: 1775587756857 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda + sha256: a1d380a93246b95051210a7523717f22cd5a714994990092e312bd61a688b15c + md5: b97631feb50f20710c402cf71e173f4b + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - libgcc >=14 + - libstdcxx >=14 + - __glibc >=2.17,<3.0.a0 + - numpy >=1.23,<3 + - python_abi 3.11.* *_cp311 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 15174736 + timestamp: 1778602614189 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda + sha256: 009408dcfdc789b8a1748d6a63fd2134ea2edc8474231ea7beba0ac3ad772a37 + md5: 15c437bfa4cbddd379b95357c9aa4150 + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - libgcc >=14 + - libstdcxx >=14 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.12.* *_cp312 + - numpy >=1.23,<3 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 14872605 + timestamp: 1778602625175 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py313hbfd7664_0.conda + sha256: a02d58327a57eb2f149c040b31c758fc6acea7c6aa5cb09b40b146eb6ed637d9 + md5: 70d4dd67877354f6912af31177cb1117 + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - libgcc >=14 + - libstdcxx >=14 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.13.* *_cp313 + - numpy >=1.23,<3 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 15001668 + timestamp: 1778602610159 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda + sha256: bf6a32c69889d38482436a786bea32276756cedf0e9805cc856ffd088e8d00f0 + md5: a5ebcefec0c12a333bcd6d7bf3bddc1f + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + size: 30949404 + timestamp: 1772730362552 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda + sha256: a44655c1c3e1d43ed8704890a91e12afd68130414ea2c0872e154e5633a13d7e + md5: 7eccb41177e15cc672e1babe9056018e + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libnsl >=2.0.1,<2.1.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libuuid >=2.41.3,<3.0a0 + - libxcrypt >=4.4.36 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 31608571 + timestamp: 1772730708989 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda + build_number: 100 + sha256: 7f77eb57648f545c1f58e10035d0d9d66b0a0efb7c4b58d3ed89ec7269afdde1 + md5: 05051be49267378d2fcd12931e319ac3 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.5,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.52.0,<4.0a0 + - libuuid >=2.42,<3.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.6,<4.0a0 + - python_abi 3.13.* *_cp313 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + license: Python-2.0 + size: 37358322 + timestamp: 1775614712638 + python_site_packages_path: lib/python3.13/site-packages +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + sha256: 12ffde5a6f958e285aa22c191ca01bbd3d6e710aa852e00618fa6ddc59149002 + md5: d7d95fc8287ea7bf33e0e7116d2b95ec + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 345073 + timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda + sha256: 3ae2ff1d1cc5930de2ca6ac03216118bdf13b2af6098e28e827f1ba25bfcbc4e + md5: 089de2ee37e4e19885c985a4fe4aaf14 + depends: + - __glibc >=2.17,<3.0.a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=14 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + size: 17303931 + timestamp: 1779874783665 +- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py312h54fa4ab_1.conda + sha256: d5ac05ad45c0d48731eb189c2cbb2bb99f0e3cb7e1acaad373cb2f1f2597fc75 + md5: 15995ecb2ef890778ba9a3750190f09d + depends: + - __glibc >=2.17,<3.0.a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=14 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + size: 16828243 + timestamp: 1779874781187 +- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_1.conda + sha256: 2ecb1a3d6aacd20e279a72196954bc8de2e83302823f9dd9f8b9b3310d1bf515 + md5: 4b098461b0b5edff1a9359c25e675cfd + depends: + - __glibc >=2.17,<3.0.a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=14 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + size: 17184702 + timestamp: 1779874789436 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + sha256: cafeec44494f842ffeca27e9c8b0c27ed714f93ac77ddadc6aaf726b5554ebac + md5: cffd3bdd58090148f4cfcd831f4b26ab + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + constrains: + - xorg-libx11 >=1.8.12,<2.0a0 + license: TCL + license_family: BSD + size: 3301196 + timestamp: 1769460227866 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + sha256: 68f0206ca6e98fea941e5717cec780ed2873ffabc0e1ed34428c061e2c6268c7 + md5: 4a13eeac0b5c8e5b8ab496e6c4ddd829 + depends: + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + size: 601375 + timestamp: 1764777111296 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + sha256: 9812a303a1395e1dafbd92e5bc8a1ff6013bcbba0a09c7f03a8d23e43560aa9b + md5: 489b8e97e666c93f68fdb35c3c9b957f + depends: + - __unix + license: ISC + size: 129868 + timestamp: 1779289852439 +- conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 + md5: 962b9857ee8e7018c22f2776ffa0b2d7 + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + size: 27011 + timestamp: 1733218222191 +- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + sha256: ee6cf346d017d954255bbcbdb424cddea4d14e4ed7e9813e429db1d795d01144 + md5: 8e662bd460bda79b1ea39194e3c4c9ab + depends: + - python >=3.10 + - typing_extensions >=4.6.0 + license: MIT and PSF-2.0 + size: 21333 + timestamp: 1763918099466 +- conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + sha256: e1a9e3b1c8fe62dc3932a616c284b5d8cbe3124bbfbedcf4ce5c828cb166ee19 + md5: 9614359868482abba1bd15ce465e3c42 + depends: + - python >=3.10 + license: MIT + license_family: MIT + size: 13387 + timestamp: 1760831448842 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 + md5: 4c06a92e74452cfa53623a81592e8934 + depends: + - python >=3.8 + - python + license: Apache-2.0 + license_family: APACHE + size: 91574 + timestamp: 1777103621679 +- conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e + md5: d7585b6550ad04c8c5e21097ada2888e + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + size: 25877 + timestamp: 1764896838868 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + sha256: cf70b2f5ad9ae472b71235e5c8a736c9316df3705746de419b59d442e8348e86 + md5: 16c18772b340887160c79a6acc022db0 + depends: + - python >=3.10 + license: BSD-2-Clause + license_family: BSD + size: 893031 + timestamp: 1774796815820 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + sha256: 960f59442173eee0731906a9077bd5ccf60f4b4226f05a22d1728ab9a21a879c + md5: 6a991452eadf2771952f39d43615bb3e + depends: + - colorama >=0.4 + - pygments >=2.7.2 + - python >=3.10 + - iniconfig >=1.0.1 + - packaging >=22 + - pluggy >=1.5,<2 + - tomli >=1 + - exceptiongroup >=1 + - python + constrains: + - pytest-faulthandler >=2 + license: MIT + license_family: MIT + size: 299984 + timestamp: 1775644472530 +- conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + sha256: 44e42919397bd00bfaa47358a6ca93d4c21493a8c18600176212ec21a8d25ca5 + md5: 67d1790eefa81ed305b89d8e314c7923 + depends: + - coverage >=7.10.6 + - pluggy >=1.2 + - pytest >=7 + - python >=3.10 + - python + license: MIT + license_family: MIT + size: 29559 + timestamp: 1774139250481 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 + md5: 5b8d21249ff20967101ffa321cab24e8 + depends: + - python >=3.9 + - six >=1.5 + - python + license: Apache-2.0 + license_family: APACHE + size: 233310 + timestamp: 1751104122689 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + build_number: 8 + sha256: fddf123692aa4b1fc48f0471e346400d9852d96eeed77dbfdd746fa50a8ff894 + md5: 8fcb6b0e2161850556231336dae58358 + constrains: + - python 3.11.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 7003 + timestamp: 1752805919375 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda + build_number: 8 + sha256: 80677180dd3c22deb7426ca89d6203f1c7f1f256f2d5a94dc210f6e758229809 + md5: c3efd25ac4d74b1584d2f7a57195ddf1 + constrains: + - python 3.12.* *_cpython + license: BSD-3-Clause + license_family: BSD + size: 6958 + timestamp: 1752805918820 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + build_number: 8 + sha256: 210bffe7b121e651419cb196a2a63687b087497595c9be9d20ebe97dd06060a7 + md5: 94305520c52a4aa3f6c2b1ff6008d9f8 + constrains: + - python 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + size: 7002 + timestamp: 1752805902938 +- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d + md5: 3339e3b65d58accf4ca4fb8748ab16b3 + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + size: 18455 + timestamp: 1753199211006 +- conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + sha256: 91cafdb64268e43e0e10d30bd1bef5af392e69f00edd34dfaf909f69ab2da6bd + md5: b5325cf06a000c5b14970462ff5e4d58 + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + size: 21561 + timestamp: 1774492402955 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 + md5: 0caa1af407ecff61170c9437a808404d + depends: + - python >=3.10 + - python + license: PSF-2.0 + license_family: PSF + size: 51692 + timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c + md5: ad659d0a2b3e47e38d829aa8cad2d610 + license: LicenseRef-Public-Domain + size: 119135 + timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + build_number: 7 + sha256: 30006902a9274de8abdad5a9f02ef7c8bb3d69a503486af0c1faee30b023e5b7 + md5: eaac87c21aff3ed21ad9656697bb8326 + depends: + - llvm-openmp >=9.0.1 + license: BSD-3-Clause + license_family: BSD + size: 8328 + timestamp: 1764092562779 +- conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + sha256: 9f242f13537ef1ce195f93f0cc162965d6cc79da578568d6d8e50f70dd025c42 + md5: 4173ac3b19ec0a4f400b4f782910368b + depends: + - __osx >=10.13 + license: bzip2-1.0.6 + license_family: BSD + size: 133427 + timestamp: 1771350680709 +- conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda + sha256: 286d4d6bf016f56d71f58c2dd495410213fb5e4053a0545d48638bfd346683bc + md5: 145a45fb204a76aac34696a6fac42ece + depends: + - __osx >=11.0 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 396933 + timestamp: 1779838320779 +- conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py312heb39f77_0.conda + sha256: 5fa71aeb0be43ccf8f5b5ac4102efd23d22e44d4e713e802251d5456a90bb62c + md5: 0b1ec37d2e54ba95731d07e273228789 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 388114 + timestamp: 1779838145107 +- conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py313h035b7d0_0.conda + sha256: 24bdd78378c4b2ed32e701254c7bc0dcab74d5b366bafb6d42ba2ffd017549d4 + md5: 6f795259f9dcc6de273f1c6f626f2234 + depends: + - __osx >=11.0 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 395003 + timestamp: 1779838290292 +- conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + sha256: 1294117122d55246bb83ad5b589e2a031aacdf2d0b1f99fd338aa4394f881735 + md5: 627eca44e62e2b665eeec57a984a7f00 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 12273764 + timestamp: 1773822733780 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda + build_number: 8 + sha256: 55cf9f92a2d07c33f8a32c44ff1528ea48fd69677cc003a4532d09b71cb8a316 + md5: 7da1e8ab7c4498db9457c191d82930a3 + depends: + - libopenblas >=0.3.33,<0.3.34.0a0 + - libopenblas >=0.3.33,<1.0a0 + constrains: + - mkl <2027 + - blas 2.308 openblas + - liblapacke 3.11.0 8*_openblas + - libcblas 3.11.0 8*_openblas + - liblapack 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 19048 + timestamp: 1779860008916 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda + build_number: 8 + sha256: 50eb650a17a34ea45fe2b31e60a98632d1f8c203308014dcef93043d54612482 + md5: 4f116127b172bbba835c1e0491efd86f + depends: + - libblas 3.11.0 8_he492b99_openblas + constrains: + - liblapacke 3.11.0 8*_openblas + - blas 2.308 openblas + - liblapack 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 19049 + timestamp: 1779860025163 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + sha256: c03c298355dea54b729ed6c5f1e6dbd0e2426906039eba8aa2ba1254d005b7d8 + md5: 423373b842c3861da6cfa8c8915798ce + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 564939 + timestamp: 1780442565078 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + sha256: 460afe7ba0882e6d2fcc0ad1568dce27025110ec09c2b9ce9e3b49d61e52ce6b + md5: f95dc08366f2a452005062b5bcceac51 + depends: + - __osx >=11.0 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + size: 75654 + timestamp: 1779279058576 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + sha256: 951958d1792238006fdc6fce7f71f1b559534743b26cc1333497d46e5903a2d6 + md5: 66a0dc7464927d0853b590b6f53ba3ea + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + size: 53583 + timestamp: 1769456300951 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda + sha256: 17a5dcd818f89173db51d7d1acd77615cb77db7b4c2b5f571d4dafe559430ab5 + md5: 4bf33d5ca73f4b89d3495285a42414a4 + depends: + - _openmp_mutex + constrains: + - libgomp 15.2.0 19 + - libgcc-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 424164 + timestamp: 1778271183296 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda + sha256: 519045363b87b870be779d38f0bfd325d4b787acdaa0a2136a92c1081eff5112 + md5: d362f41203d0a1d2d4940446f95374c9 + depends: + - libgfortran5 15.2.0 hd16e46c_19 + constrains: + - libgfortran-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 139925 + timestamp: 1778271458366 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda + sha256: c7f5f6e80357d6d5bc69588c16144205b0c79cf32cd090ccb5afef9d557632af + md5: 1cddb3f7e54f5871297afc0fafa61c2c + depends: + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 1063687 + timestamp: 1778271196574 +- conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda + build_number: 8 + sha256: 56a68fce5a63d4583a42c212324d62ac292376b8bf05986a551bd640e7fa137d + md5: e11ee849bd2a573a0f6e53b1b67ebf37 + depends: + - libblas 3.11.0 8_he492b99_openblas + constrains: + - liblapacke 3.11.0 8*_openblas + - libcblas 3.11.0 8*_openblas + - blas 2.308 openblas + license: BSD-3-Clause + license_family: BSD + size: 19030 + timestamp: 1779860046842 +- conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + sha256: d9e2006051529aec5578c6efeb13bb6a7200a014b2d5a77a579e83a8049d5f3c + md5: becdfbfe7049fa248e52aa37a9df09e2 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.3.* + license: 0BSD + size: 105724 + timestamp: 1775826029494 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda + sha256: 1096c740109386607938ab9f09a7e9bca06d86770a284777586d6c378b8fb3fd + md5: ec88ba8a245855935b871a7324373105 + depends: + - __osx >=10.13 + license: BSD-2-Clause + license_family: BSD + size: 79899 + timestamp: 1769482558610 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda + sha256: 2c2ffe7c3ab7becd47ad308946873d2bdc219625af32a53d10efbaa54b595d31 + md5: 30666a6f0afe1471e999eca7ae5c8179 + depends: + - __osx >=11.0 + - libgfortran + - libgfortran5 >=14.3.0 + - llvm-openmp >=19.1.7 + constrains: + - openblas >=0.3.33,<0.3.34.0a0 + license: BSD-3-Clause + license_family: BSD + size: 6287889 + timestamp: 1776996499823 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda + sha256: 4d4f3135d390d192ab9cdf3711d87e3be6bb7f3959c52a96e2f333b30960d6fb + md5: 4c019bd25570899d0f9755de01b89021 + depends: + - __osx >=11.0 + - icu >=78.3,<79.0a0 + - libzlib >=1.3.2,<2.0a0 + license: blessing + size: 1010419 + timestamp: 1780575011758 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + sha256: 4c6da089952b2d70150c74234679d6f7ac04f4a98f9432dec724968f912691e7 + md5: 30439ff30578e504ee5e0b390afc8c65 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + size: 59000 + timestamp: 1774073052242 +- conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda + sha256: c8eeb6bca45680db8974b78e0524b2ab3c285a9916a0b3356329d1f949b1311b + md5: 301c1db2d75ac8a91f46d21652e08dd6 + depends: + - __osx >=11.0 + constrains: + - openmp 22.1.7|22.1.7.* + - intel-openmp <0.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + size: 310879 + timestamp: 1780456054580 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + sha256: f5f7e006ff4271305ab4cc08eedd855c67a571793c3d18aff73f645f088a8cae + md5: 31b8740cf1b2588d4e61c81191004061 + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + size: 831711 + timestamp: 1777423052277 +- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda + sha256: 47fa3ad9a49348efb5662d7850a433607ee4fabf259709731437a969c3006fa9 + md5: 0cb49ff5e81a76c101f1a561cf1f2a76 + depends: + - python + - __osx >=11.0 + - libcxx >=19 + - liblapack >=3.9.0,<4.0a0 + - python_abi 3.11.* *_cp311 + - libcblas >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 8593034 + timestamp: 1779169256521 +- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py312h746d82c_0.conda + sha256: e7837f62b874c987c1bd2eda335ae9b977caf61a5227c23e4e8cceef88bb21b6 + md5: 86c91d10224283ed367225057a09e4a3 + depends: + - python + - libcxx >=19 + - __osx >=11.0 + - libcblas >=3.9.0,<4.0a0 + - python_abi 3.12.* *_cp312 + - libblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 7997002 + timestamp: 1779782916096 +- conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py313hb870fc3_0.conda + sha256: 5ac50239781b7cd7581126e626f0dc13944de3fefd950b874700047d7e0aa53f + md5: 6b8ec37e54d1ef1a635038a9d6c4a672 + depends: + - python + - __osx >=11.0 + - libcxx >=19 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - python_abi 3.13.* *_cp313 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 8068573 + timestamp: 1779169285266 +- conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + sha256: 334fd49ea31b99114f5afb1ec44555dc8c90640648302a4f8f838ee345d1ec50 + md5: 5cf0ece4375c73d7a5765e83565a69c7 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + size: 2776564 + timestamp: 1775589970694 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda + sha256: 63ec8115217bdef61a20856cfaabaf814882a9ea9c8085141e20e3ff0debc23f + md5: e31c570c36ac80b7d8db81b1771622bd + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - __osx >=11.0 + - libcxx >=19 + - python_abi 3.11.* *_cp311 + - numpy >=1.23,<3 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 14558446 + timestamp: 1778602873120 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py312h8e27051_0.conda + sha256: d72b541b510e3a1db86db3ce8d4c30bddc945c3c89eb2c9d16fde0cc9f82e497 + md5: 8cfffbf760a7d7abc16c79141ead177a + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - libcxx >=19 + - __osx >=11.0 + - numpy >=1.23,<3 + - python_abi 3.12.* *_cp312 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 14170082 + timestamp: 1778602746933 +- conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py313hfd25234_0.conda + sha256: e544e54be83b7be300813a3503ca915c8a7c6e82f550e616326732a9d9d09014 + md5: 4942165df70ab41f6487ceaa0ff6bb67 + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - libcxx >=19 + - __osx >=11.0 + - numpy >=1.23,<3 + - python_abi 3.13.* *_cp313 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 14290954 + timestamp: 1778602759825 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.15-ha9537fe_0_cpython.conda + sha256: e02e12cd8d391f18bb3bf91d07e16b993592ec0d76ee37cf639390b766e0e687 + md5: 93b802a91de90b2c17b808608726bf45 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + size: 15664115 + timestamp: 1772730794934 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.13-ha9537fe_0_cpython.conda + sha256: fb592ceb1bc247d19247d5535083da4a79721553e29e1290f5d81c07d4f086b5 + md5: ec05996c0d914a4e98ee3c7d789083f8 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 13672169 + timestamp: 1772730464626 +- conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.13-h3d5d122_100_cp313.conda + build_number: 100 + sha256: 6f71b48fe93ebc0dd42c80358b75020f6ad12ed4772fb3555da36000139c0dc7 + md5: 8948c8c7c653ad668d55bbbd6836178b + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.5,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.52.0,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.6,<4.0a0 + - python_abi 3.13.* *_cp313 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + license: Python-2.0 + size: 17650454 + timestamp: 1775616128232 + python_site_packages_path: lib/python3.13/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + sha256: 4614af680aa0920e82b953fece85a03007e0719c3399f13d7de64176874b80d5 + md5: eefd65452dfe7cce476a519bece46704 + depends: + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 317819 + timestamp: 1765813692798 +- conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda + sha256: 4e68affca9e1d14cdb1fe6910c459ec4bd01b1217a867f7cfbf40830951f80aa + md5: 972007d34efaf5755603391a91e7d50f + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + size: 15513987 + timestamp: 1779875850168 +- conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda + sha256: 4b3663a4f1a92c881ba0fc4d317eee04831adc44400d85bac5b27c503445f6ad + md5: 284f71322e48e8ae8ce23d48356df042 + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + size: 15137152 + timestamp: 1779876260804 +- conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda + sha256: d19a981b1cf0dc11b91a049caa3c983dba49161175c21c8f28c1c9114799c9e0 + md5: 8543e2546bb797f336d4469a41c16f18 + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + size: 15365931 + timestamp: 1779875663184 +- conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + sha256: 7f0d9c320288532873e2d8486c331ec6d87919c9028208d3f6ac91dc8f99a67b + md5: 6e6efb7463f8cef69dbcb4c2205bf60e + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + size: 3282953 + timestamp: 1769460532442 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + build_number: 7 + sha256: 7acaa2e0782cad032bdaf756b536874346ac1375745fb250e9bdd6a48a7ab3cd + md5: a44032f282e7d2acdeb1c240308052dd + depends: + - llvm-openmp >=9.0.1 + license: BSD-3-Clause + license_family: BSD + size: 8325 + timestamp: 1764092507920 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + sha256: 540fe54be35fac0c17feefbdc3e29725cce05d7367ffedfaaa1bdda234b019df + md5: 620b85a3f45526a8bc4d23fd78fc22f0 + depends: + - __osx >=11.0 + license: bzip2-1.0.6 + license_family: BSD + size: 124834 + timestamp: 1771350416561 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda + sha256: d9475f473084602003da38e373604b48b674b5fbd5939eb6f26b757cbda89f28 + md5: 2e3107762a2b8bb31093fe14bab1fe17 + depends: + - __osx >=11.0 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 397978 + timestamp: 1779838426505 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py312h04c11ed_0.conda + sha256: 62f7590a0e6456ff8f534c3f6213e4ec50443d3409fa3babfa30a38822a2b0fa + md5: 86b295185747ca5b09e95d7d33280382 + depends: + - __osx >=11.0 + - python >=3.12,<3.13.0a0 + - python >=3.12,<3.13.0a0 *_cpython + - python_abi 3.12.* *_cp312 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 388500 + timestamp: 1779838256904 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py313h65a2061_0.conda + sha256: 46d98e0d517ecf6bff6160b2200a27f88da681786d4eb223cd5949d73a0b7610 + md5: e3f15d7b559de10dd9f60bd345efcdaa + depends: + - __osx >=11.0 + - python >=3.13,<3.14.0a0 + - python >=3.13,<3.14.0a0 *_cp313 + - python_abi 3.13.* *_cp313 + - tomli + license: Apache-2.0 + license_family: APACHE + size: 396380 + timestamp: 1779838267496 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + sha256: 3a7907a17e9937d3a46dfd41cffaf815abad59a569440d1e25177c15fd0684e5 + md5: f1182c91c0de31a7abd40cedf6a5ebef + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 12361647 + timestamp: 1773822915649 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda + build_number: 8 + sha256: 8f5ec18ead0619a9cf0f38b49796c22f6fc0f44850c0df2baea0f5277db16e75 + md5: dbfe729181a32741ae63ecb41eefbac6 + depends: + - libopenblas >=0.3.33,<0.3.34.0a0 + - libopenblas >=0.3.33,<1.0a0 + constrains: + - blas 2.308 openblas + - liblapack 3.11.0 8*_openblas + - liblapacke 3.11.0 8*_openblas + - libcblas 3.11.0 8*_openblas + - mkl <2027 + license: BSD-3-Clause + license_family: BSD + size: 18949 + timestamp: 1779859141315 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda + build_number: 8 + sha256: f93efcd44bc24f97c2478c7474d3baa6801a057974f330e1d06bedc33e4c778f + md5: 03a2ef3491da9e5b4d18c03e9f4b3109 + depends: + - libblas 3.11.0 8_h51639a9_openblas + constrains: + - blas 2.308 openblas + - liblapack 3.11.0 8*_openblas + - liblapacke 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 18911 + timestamp: 1779859147634 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + sha256: cceb668dc1b71f054b1036dd83eca2e02c0c3a4b2ba3ad28c74a982d819597a3 + md5: 0325fbe13eb6dd39234eb305ac1b3cb8 + depends: + - __osx >=11.0 + license: Apache-2.0 WITH LLVM-exception + license_family: Apache + size: 568252 + timestamp: 1780441702930 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + sha256: 3133fb6bfa871288b92c8b8752696686a841bf4ffe035aa3038033c9e15b738e + md5: ef22e9ab1dc7c2f334252f565f90b3b8 + depends: + - __osx >=11.0 + constrains: + - expat 2.8.1.* + license: MIT + license_family: MIT + size: 69110 + timestamp: 1779278728511 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + sha256: 6686a26466a527585e6a75cc2a242bf4a3d97d6d6c86424a441677917f28bec7 + md5: 43c04d9cb46ef176bb2a4c77e324d599 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + size: 40979 + timestamp: 1769456747661 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda + sha256: 06644fa4d34d57c9e48f4d84b1256f9e5f654fdb37f43acc8a58a396952d42b7 + md5: 644058123986582db33aebd4ae2ca184 + depends: + - _openmp_mutex + constrains: + - libgcc-ng ==15.2.0=*_19 + - libgomp 15.2.0 19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 404080 + timestamp: 1778273064154 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda + sha256: d4837b3b9b30af3132d260225e91ab9dde83be04c59513f500cc81050fb37486 + md5: 1ea03f87cdb1078fbc0e2b2deb63752c + depends: + - libgfortran5 15.2.0 hdae7583_19 + constrains: + - libgfortran-ng ==15.2.0=*_19 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 139675 + timestamp: 1778273280875 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda + sha256: d0a68b7a121d115b80c169e24d1265dcc25a3fe58d107df1bbc430797e226d88 + md5: ba36d8c606a6a53fe0b8c12d47267b3d + depends: + - libgcc >=15.2.0 + constrains: + - libgfortran 15.2.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + size: 599691 + timestamp: 1778273075448 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda + build_number: 8 + sha256: 8a076fe82142a00fe85f5a5a5351e286e8064f0100fe13608d19182cd0018c25 + md5: 85adeb3d469d082dbd9c8c39e36dec57 + depends: + - libblas 3.11.0 8_h51639a9_openblas + constrains: + - libcblas 3.11.0 8*_openblas + - blas 2.308 openblas + - liblapacke 3.11.0 8*_openblas + license: BSD-3-Clause + license_family: BSD + size: 18925 + timestamp: 1779859153970 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + sha256: 34878d87275c298f1a732c6806349125cebbf340d24c6c23727268184bba051e + md5: b1fd823b5ae54fbec272cea0811bd8a9 + depends: + - __osx >=11.0 + constrains: + - xz 5.8.3.* + license: 0BSD + size: 92472 + timestamp: 1775825802659 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda + sha256: 1089c7f15d5b62c622625ec6700732ece83be8b705da8c6607f4dabb0c4bd6d2 + md5: 57c4be259f5e0b99a5983799a228ae55 + depends: + - __osx >=11.0 + license: BSD-2-Clause + license_family: BSD + size: 73690 + timestamp: 1769482560514 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda + sha256: 9dd455b2d172aeedfa2058d324b5b5822b0bc1b7c1f32cd183d7078540d2f6eb + md5: 909e41855c29f0d52ae630198cd57135 + depends: + - __osx >=11.0 + - libgfortran + - libgfortran5 >=14.3.0 + - llvm-openmp >=19.1.7 + constrains: + - openblas >=0.3.33,<0.3.34.0a0 + license: BSD-3-Clause + license_family: BSD + size: 4304965 + timestamp: 1776995497368 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda + sha256: 862463917e8ef5ac3ebdaf8f19914634b457609cc27ba678b7197124cefeb1f7 + md5: 1ebde5c677f00765233a17e278571177 + depends: + - __osx >=11.0 + - icu >=78.3,<79.0a0 + - libzlib >=1.3.2,<2.0a0 + license: blessing + size: 927724 + timestamp: 1780575223548 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + sha256: 361415a698514b19a852f5d1123c5da746d4642139904156ddfca7c922d23a05 + md5: bc5a5721b6439f2f62a84f2548136082 + depends: + - __osx >=11.0 + constrains: + - zlib 1.3.2 *_2 + license: Zlib + license_family: Other + size: 47759 + timestamp: 1774072956767 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda + sha256: 6bf27376f11198c01a88a1c8234470f45bce0aa7502b7e7988ef03ef5db3a890 + md5: 7c6a5897a8bc5b6d509a4ee9dec7fcc8 + depends: + - __osx >=11.0 + constrains: + - openmp 22.1.7|22.1.7.* + - intel-openmp <0.0a0 + license: Apache-2.0 WITH LLVM-exception + license_family: APACHE + size: 285162 + timestamp: 1780455637760 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + sha256: 4ea6c620b87bd1d42bb2ccc2c87cd2483fa2d7f9e905b14c223f11ff3f4c455d + md5: 343d10ed5b44030a2f67193905aea159 + depends: + - __osx >=11.0 + license: X11 AND BSD-3-Clause + size: 805509 + timestamp: 1777423252320 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda + sha256: 08e5062ab9bce23adef1c62282a99d035780e43eb8a843b0f11d8a1e967fe123 + md5: 7738446d4be7ac8b56e6d6e3bdb7e52b + depends: + - python + - libcxx >=19 + - __osx >=11.0 + - python_abi 3.11.* *_cp311 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - liblapack >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 7456206 + timestamp: 1779169211856 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda + sha256: b09e03dace335a6f303352fc4e167243e04d7026d55008546fa643d224fb0bad + md5: 9f554fdfa902971390975b489e678c03 + depends: + - python + - __osx >=11.0 + - libcxx >=19 + - python_abi 3.12.* *_cp312 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 6843172 + timestamp: 1779169213435 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py313hce9b930_0.conda + sha256: 3f79e4755d6feafe2d9ce9e42cf28a2054ce404c5b9a89fde16eb48fd25e89c5 + md5: 13243cfdfeece38ffd42780e315129cf + depends: + - python + - __osx >=11.0 + - libcxx >=19 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + - python_abi 3.13.* *_cp313 + - libcblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + size: 6928597 + timestamp: 1779169217159 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + sha256: c91bf510c130a1ea1b6ff023e28bac0ccaef869446acd805e2016f69ebdc49ea + md5: 25dcccd4f80f1638428613e0d7c9b4e1 + depends: + - __osx >=11.0 + - ca-certificates + license: Apache-2.0 + license_family: Apache + size: 3106008 + timestamp: 1775587972483 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda + sha256: a220a05380062dce89512f60a85aaf754beeea7774e66c57116e3d7323738391 + md5: b3ff79b6b7aca8a977cc29f2962c2f47 + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - python 3.11.* *_cpython + - libcxx >=19 + - __osx >=11.0 + - python_abi 3.11.* *_cp311 + - numpy >=1.23,<3 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 14329411 + timestamp: 1778602822615 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py312h6510ced_0.conda + sha256: 7202013525593f57a452dac7e5fee9f26478822be3ba5c893643517b8627406d + md5: 4581a32b837950217327fcab93214313 + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - __osx >=11.0 + - python 3.12.* *_cpython + - libcxx >=19 + - python_abi 3.12.* *_cp312 + - numpy >=1.23,<3 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 13926263 + timestamp: 1778602825408 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py313h1188861_0.conda + sha256: 5fd41083894c2b7b9ba3f02a0d4ddbab17c6c1f645fdc1f3f1325522eb2a1a28 + md5: 12dd2c60321105aa1f869373ae27de42 + depends: + - python + - numpy >=1.26.0 + - python-dateutil >=2.8.2 + - libcxx >=19 + - __osx >=11.0 + - python 3.13.* *_cp313 + - numpy >=1.23,<3 + - python_abi 3.13.* *_cp313 + constrains: + - adbc-driver-postgresql >=1.2.0 + - adbc-driver-sqlite >=1.2.0 + - beautifulsoup4 >=4.12.3 + - blosc >=1.21.3 + - bottleneck >=1.4.2 + - fastparquet >=2024.11.0 + - fsspec >=2024.10.0 + - gcsfs >=2024.10.0 + - html5lib >=1.1 + - hypothesis >=6.116.0 + - jinja2 >=3.1.5 + - lxml >=5.3.0 + - matplotlib >=3.9.3 + - numba >=0.60.0 + - numexpr >=2.10.2 + - odfpy >=1.4.1 + - openpyxl >=3.1.5 + - psycopg2 >=2.9.10 + - pyarrow >=13.0.0 + - pyiceberg >=0.8.1 + - pymysql >=1.1.1 + - pyqt5 >=5.15.9 + - pyreadstat >=1.2.8 + - pytables >=3.10.1 + - pytest >=8.3.4 + - pytest-xdist >=3.6.1 + - python-calamine >=0.3.0 + - pytz >=2024.2 + - pyxlsb >=1.0.10 + - qtpy >=2.4.2 + - scipy >=1.14.1 + - s3fs >=2024.10.0 + - sqlalchemy >=2.0.36 + - tabulate >=0.9.0 + - xarray >=2024.10.0 + - xlrd >=2.0.1 + - xlsxwriter >=3.2.0 + - zstandard >=0.23.0 + license: BSD-3-Clause + license_family: BSD + size: 14056402 + timestamp: 1778602842319 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.15-h8561d8f_0_cpython.conda + sha256: 9a846065863925b2562126a5c6fecd7a972e84aaa4de9e686ad3715ca506acfa + md5: 49c7d96c58b969585cf09fb01d74e08e + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.11.* *_cp311 + license: Python-2.0 + size: 14753109 + timestamp: 1772730203101 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.13-h8561d8f_0_cpython.conda + sha256: e658e647a4a15981573d6018928dec2c448b10c77c557c29872043ff23c0eb6a + md5: 8e7608172fa4d1b90de9a745c2fd2b81 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.4,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libsqlite >=3.51.2,<4.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.5,<4.0a0 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + constrains: + - python_abi 3.12.* *_cp312 + license: Python-2.0 + size: 12127424 + timestamp: 1772730755512 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda + build_number: 100 + sha256: d0fffc5fde21d1ae350da545dfb9e115a8c53bed8a9c5761f9efd4a5581853c1 + md5: 9991a930e81d3873eba7a299ba783ec4 + depends: + - __osx >=11.0 + - bzip2 >=1.0.8,<2.0a0 + - libexpat >=2.7.5,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - liblzma >=5.8.2,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.52.0,<4.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.6,<4.0a0 + - python_abi 3.13.* *_cp313 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + license: Python-2.0 + size: 12966447 + timestamp: 1775615694085 + python_site_packages_path: lib/python3.13/site-packages +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + sha256: a77010528efb4b548ac2a4484eaf7e1c3907f2aec86123ed9c5212ae44502477 + md5: f8381319127120ce51e081dce4865cf4 + depends: + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + size: 313930 + timestamp: 1765813902568 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda + sha256: b45f87414da242a9e40eb934e89513a856e6236d681611c2c9a21d074b03ef5a + md5: 15f96f91b13cbefddbf998368d06adef + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + size: 13954661 + timestamp: 1779874558902 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda + sha256: c0ed2cbfa3485bac8570e52b577475778c603ee92d078a8b164d1ddec992e577 + md5: 173d5eeba324363d9171946e86a81687 + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.12,<3.13.0a0 + - python_abi 3.12.* *_cp312 + license: BSD-3-Clause + license_family: BSD + size: 13936510 + timestamp: 1779874824714 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda + sha256: b828f5d0f77e890bc5ec8b2a391bf27c01d468a8b83667bf7786e9a6a1ff12e8 + md5: f441d9cefca60be8589c309e3af2e6d8 + depends: + - __osx >=11.0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - numpy <2.7 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + size: 14049103 + timestamp: 1779874780525 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + sha256: 799cab4b6cde62f91f750149995d149bc9db525ec12595e8a1d91b9317f038b3 + md5: a9d86bc62f39b94c4661716624eb21b0 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + size: 3127137 + timestamp: 1769460817696 diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 0000000..6ebb640 --- /dev/null +++ b/pixi.toml @@ -0,0 +1,35 @@ +[workspace] +name = "pybeh_pd" +description = "Pandas-friendly wrappers around pybeh for free-recall behavioral analysis" +channels = ["conda-forge"] +platforms = ["linux-64", "osx-64", "osx-arm64"] + +[dependencies] +python = ">=3.11,<3.14" +numpy = ">=1.24" +pandas = ">=2.0" +scipy = ">=1.10" + +[feature.test.dependencies] +pytest = ">=7" +pytest-cov = "*" + +[feature.py311.dependencies] +python = "3.11.*" +[feature.py312.dependencies] +python = "3.12.*" +[feature.py313.dependencies] +python = "3.13.*" + +[environments] +default = ["test"] +py311 = ["py311", "test"] +py312 = ["py312", "test"] +py313 = ["py313", "test"] + +[tasks] +# Pure-Python package: no compiled extensions to build. This task is the +# stand-in for "build" and just confirms the modules import. +build = "python -c \"import pybeh_pd; print('pybeh_pd import OK')\"" +test = "pytest -q" +test-cov = "pytest -q --cov=pybeh_pd --cov=pybeh_copy --cov-report=term-missing" From 1a23819c19163c30d2ec3d3c3856304c9a87da68 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 01:01:46 +0000 Subject: [PATCH 05/15] test: add behavior-lock regression suite (Phase 4 gate) Golden-master capture/replay locking current numerical output for all 29 public functions across 3 seeded synthetic experiments + a repeated-presentation case. golden.npz captured on numpy 1.24/pandas 2.3; suite passes identically on numpy 2.4/pandas 3.0. Two known-broken behaviors (undefined `mat` in loftus_masson_unequal_variance_kahana; IndexError in pd_min_temp_fact default path) are pinned as pytest.raises and logged in bug_report.md. --- tests/factories.py | 110 ++++++++++++++++++++ tests/regression/capture_golden.py | 31 ++++++ tests/regression/cases.py | 154 ++++++++++++++++++++++++++++ tests/regression/golden.npz | Bin 0 -> 85530 bytes tests/regression/test_regression.py | 78 ++++++++++++++ 5 files changed, 373 insertions(+) create mode 100644 tests/factories.py create mode 100644 tests/regression/capture_golden.py create mode 100644 tests/regression/cases.py create mode 100644 tests/regression/golden.npz create mode 100644 tests/regression/test_regression.py diff --git a/tests/factories.py b/tests/factories.py new file mode 100644 index 0000000..935fcdb --- /dev/null +++ b/tests/factories.py @@ -0,0 +1,110 @@ +"""Fixture factories for pybeh_pd regression/behavior tests. + +These synthesize the two data structures the package operates on: + +1. **pybeh matrices** — ``pres_itemnos`` / ``rec_itemnos`` (and the derived + recalls matrix), as consumed by the matrix-level functions (``crp``, + ``temp_fact``, ``sem_crp``, ``dist_fact``, ...). +2. **long-format event DataFrames** — one row per presentation / recall / + word-value event, as consumed by the ``pd_*`` wrappers. + +Everything is seeded so captures are reproducible. A simulated free-recall +"experiment" presents items 1..list_length on each list and recalls a random +ordering of a subset, optionally inserting extra-list intrusions (-1) and +repeats, mirroring the matrix conventions the code documents. +""" +from __future__ import annotations + +import numpy as np +import pandas as pd + + +def make_experiment( + n_lists=6, + list_length=8, + n_features=5, + p_recall=0.7, + p_intrusion=0.1, + seed=0, +): + """Simulate one subject's free-recall experiment. + + Returns a dict with the pybeh-style matrices and a long-format events + DataFrame (columns: subject, session, list, type, itemno + feature columns + ``f0..f{n_features-1}`` on the WORD_VALS rows). + """ + rng = np.random.default_rng(seed) + pool_size = n_lists * list_length + + # Stable semantic features per pool item (itemnos are 1-based). + features = rng.normal(size=(pool_size, n_features)) + + pres_rows = [] + rec_rows = [] + pres_itemnos = [] + rec_itemnos = [] + max_recs = 0 + + for li in range(n_lists): + itemnos = np.arange(li * list_length, (li + 1) * list_length) + 1 + pres_itemnos.append(itemnos.tolist()) + for pos, ino in enumerate(itemnos): + # Presentation rows also carry the item's semantic features, so the + # per-list `pd_*_list` API (which reads features off the WORD rows, + # not separate WORD_VALS rows) can be exercised. + prow: dict[str, object] = dict( + subject="s0", session=0, list=li, type="WORD", + itemno=int(ino), serialpos=pos + 1) + for j in range(n_features): + prow[f"f{j}"] = float(features[ino - 1, j]) + pres_rows.append(prow) + + # Recall a random subset in a random order. + recalled_mask = rng.random(list_length) < p_recall + recalled = itemnos[recalled_mask] + rng.shuffle(recalled) + recalled = list(recalled) + # Maybe insert an extra-list intrusion (itemno not in this list -> -1 + # at the matrix level; here use a pool item from another list). + if rng.random() < p_intrusion and pool_size > list_length: + outside = [i for i in range(1, pool_size + 1) + if i not in set(itemnos.tolist())] + recalled.insert(rng.integers(0, len(recalled) + 1), + int(rng.choice(outside))) + + rec_itemnos.append([int(x) for x in recalled]) + max_recs = max(max_recs, len(recalled)) + for pos, ino in enumerate(recalled): + rec_rows.append( + dict(subject="s0", session=0, list=li, type="REC_WORD", + itemno=int(ino), serialpos=pos + 1) + ) + + # Word-value rows (semantic features) — one per pool item, itemnos 1-based. + feat_cols = [f"f{j}" for j in range(n_features)] + wv_rows = [] + for ino in range(1, pool_size + 1): + row: dict[str, object] = dict( + subject="s0", session=0, list=-1, type="WORD_VALS", + itemno=ino, serialpos=0) + for j, c in enumerate(feat_cols): + row[c] = float(features[ino - 1, j]) + wv_rows.append(row) + + events = pd.DataFrame(pres_rows + rec_rows + wv_rows) + + # Rectangular matrices padded with zeros (the matrix convention). + pres_mat = np.array(pres_itemnos, dtype=int) + rec_mat = np.zeros((n_lists, max(max_recs, 1)), dtype=int) + for i, r in enumerate(rec_itemnos): + rec_mat[i, : len(r)] = r + + return dict( + events=events, + pres_itemnos=pres_mat, + rec_itemnos=rec_mat, + features=features, + feat_cols=feat_cols, + list_length=list_length, + n_lists=n_lists, + ) diff --git a/tests/regression/capture_golden.py b/tests/regression/capture_golden.py new file mode 100644 index 0000000..599389c --- /dev/null +++ b/tests/regression/capture_golden.py @@ -0,0 +1,31 @@ +"""Capture golden-master outputs for the behavior-lock regression suite. + +Run ONCE to freeze current behavior: + + python tests/regression/capture_golden.py + +Writes ``golden.npz`` next to this file. The replay test compares live output +against it. Re-run only when an *intended* behavior change has been reviewed and +approved (it should not happen during this renovation). +""" +from __future__ import annotations + +import os + +import numpy as np + +from cases import build_cases + + +def main(): + cases = build_cases() + out = os.path.join(os.path.dirname(__file__), "golden.npz") + np.savez(out, **{k: np.asarray(v, dtype=float) for k, v in cases.items()}) + print(f"wrote {len(cases)} golden cases -> {out}") + for k in sorted(cases): + v = np.asarray(cases[k], dtype=float) + print(f" {k:34s} shape={v.shape}") + + +if __name__ == "__main__": + main() diff --git a/tests/regression/cases.py b/tests/regression/cases.py new file mode 100644 index 0000000..7aed6e7 --- /dev/null +++ b/tests/regression/cases.py @@ -0,0 +1,154 @@ +"""Single source of truth for behavior-lock regression cases. + +Both the golden-capture script (``capture_golden.py``) and the replay test +(``test_regression.py``) import :func:`build_cases`, so the set of cases and how +each result is reduced to a numpy array can never drift between capture and check. + +Each case maps a string name to a float ndarray (NaNs allowed; compared with +``np.isclose(..., equal_nan=True)``). Results that are DataFrames or tuples are +reduced here to arrays. The known-broken +``loftus_masson_unequal_variance_kahana`` is intentionally excluded (it raises; +that behavior is locked separately in the test via ``pytest.raises``). +""" +from __future__ import annotations + +import os +import sys + +import numpy as np + +_HERE = os.path.dirname(__file__) +sys.path.insert(0, os.path.join(_HERE, "..")) # tests/ (factories) +sys.path.insert(0, os.path.join(_HERE, "..", "..")) # repo root (pybeh_pd) +import pybeh_pd as pb # noqa: E402 +from factories import make_experiment # noqa: E402 + + +def _arr(x): + return np.asarray(x, dtype=float) + + +def _repeated_pres_case(): + """A hand-built repeated-presentation case for the max_n_reps>1 / 3D paths. + + Two trials, list length 4, item 2 presented twice (serial positions 2 and 4). + """ + pres = np.array([[1, 2, 3, 2], [1, 2, 3, 2]]) + rec = np.array([[2, 1, 3, 0], [3, 2, 1, 0]]) + return pres, rec + + +def build_cases(): + cases: dict[str, np.ndarray] = {} + + # --- matrix-level functions over several seeded experiments ------------- + for seed in (0, 1, 2): + ex = make_experiment(seed=seed) + pres, rec, ll = ex["pres_itemnos"], ex["rec_itemnos"], ex["list_length"] + subs = ["_"] * pres.shape[0] + recalls = pb.make_recalls_matrix(pres, rec) + poss = pb.make_poss_recalls_matrix(pres) + sims = pb.get_sim_mat(ex["events"], ex["feat_cols"]) + + p = f"seed{seed}" + cases[f"make_recalls_matrix__{p}"] = _arr(recalls) + cases[f"make_poss_recalls_matrix__{p}"] = _arr(poss) + cases[f"clean_mask__{p}"] = _arr(pb.make_clean_recalls_mask2d(recalls)) + cases[f"crp__{p}"] = _arr(pb.crp(recalls=recalls, subjects=subs, + listLength=ll, lag_num=4)) + cases[f"temp_fact__{p}"] = _arr(pb.temp_fact(recalls=recalls, + subjects=subs, listLength=ll)) + bin_means, crp = pb.sem_crp(recalls=recalls, recalls_itemnos=rec, + pres_itemnos=pres, subjects=subs, + sem_sims=sims, n_bins=5, listLength=ll) + cases[f"sem_crp_binmeans__{p}"] = _arr(bin_means) + cases[f"sem_crp_crp__{p}"] = _arr(crp) + cases[f"dist_fact__{p}"] = _arr(pb.dist_fact(rec_itemnos=rec, + pres_itemnos=pres, + subjects=subs, dist_mat=sims)) + cases[f"get_sim_mat__{p}"] = _arr(sims) + + # --- repeated-presentation (3D) paths: min_crp / min_temp_fact ---------- + pres_r, rec_r = _repeated_pres_case() + subs_r = ["_", "_"] + recalls3d = pb.make_recalls_matrix(pres_r, rec_r, max_n_reps=2) + poss3d = pb.make_poss_recalls_matrix(pres_r, max_n_reps=2) + cases["make_recalls_matrix__rep3d"] = _arr(recalls3d) + cases["make_poss_recalls_matrix__rep3d"] = _arr(poss3d) + cases["min_crp__rep"] = _arr(pb.min_crp(recalls=recalls3d, poss_recalls=poss3d, + subjects=subs_r, listLength=4, lag_num=3)) + cases["min_temp_fact__rep"] = _arr(pb.min_temp_fact( + recalls=recalls3d, poss_recalls=poss3d, subjects=subs_r, listLength=4)) + + # --- helpers ------------------------------------------------------------ + cases["get_min_trans"] = _arr([pb.get_min_trans([3, 1], [2]), + pb.get_min_trans([5], [2, 4]), + pb.get_min_trans([1, 4], [4])]) + # Helpers are called internally with numpy scalars + numpy arrays; mirror that + # (a Python-int `actual` takes a different, numpy-2-incompatible 0-d path). + cases["temp_percentile_rank"] = _arr([ + pb.temp_percentile_rank(np.int64(2), np.array([1, 2, 3, 4])), + pb.temp_percentile_rank(np.int64(3), np.array([3, 3, 1])), + np.nan if pb.temp_percentile_rank(np.int64(1), np.array([1])) is None else 0.0, + ]) + cases["dist_percentile_rank"] = _arr([ + pb.dist_percentile_rank(np.float64(0.5), np.array([0.1, 0.5, 0.9])), + pb.dist_percentile_rank(np.float64(0.5), np.array([0.1, 0.5, 0.9]), + is_similarity=True), + ]) + + # --- pandas wrappers ---------------------------------------------------- + for seed in (0, 1, 2): + ex = make_experiment(seed=seed) + df, fc = ex["events"], ex["feat_cols"] + p = f"seed{seed}" + cases[f"pd_crp__{p}"] = _arr(pb.pd_crp(df)["prob"].values) + cases[f"pd_min_crp__{p}"] = _arr(pb.pd_min_crp(df)["prob"].values) + cases[f"pd_temp_fact__{p}"] = _arr([pb.pd_temp_fact(df)]) + # pd_min_temp_fact(df) with the default max_n_reps=1 raises (bug B4); the + # raise is locked in the test. Capture the working max_n_reps=2 path here. + cases[f"pd_min_temp_fact_r2__{p}"] = _arr([pb.pd_min_temp_fact(df, max_n_reps=2)]) + cases[f"pd_dist_fact__{p}"] = _arr([pb.pd_dist_fact(df, sim_columns=fc)]) + cases[f"pd_sem_crp__{p}"] = _arr(pb.pd_sem_crp(df, sim_columns=fc)["prob"].values) + cases[f"get_itemno_matrices__{p}"] = _arr( + pb.get_itemno_matrices(df.query("type == 'WORD'").copy())) + pres_m, rec_m, recalls_m = pb.get_all_matrices(df) + cases[f"get_all_matrices_pres__{p}"] = _arr(pres_m) + cases[f"get_all_matrices_recalls__{p}"] = _arr(recalls_m) + + # --- per-list / per-subject aggregating variants (groupby.apply paths) --- + # These read semantic features off the WORD rows directly (serialpos-indexed). + bins = [0.0, 2.0, 3.0, 4.0, 5.0] + for seed in (0, 1): + ex = make_experiment(seed=seed) + df, fc = ex["events"], ex["feat_cols"] + li = f"seed{seed}" + one_list = df.query("list == 0").copy() + dfl = pb.pd_dist_fact_list(one_list, sim_columns=fc) + cases[f"pd_dist_fact_list_df__{li}"] = _arr(dfl["dist_fact"].values) + cases[f"pd_dist_fact_list_tc__{li}"] = _arr( + [dfl["total"].values[0], dfl["count"].values[0]]) + sl = pb.pd_sem_crp_list(one_list, sim_columns=fc, bins=bins) + cases[f"pd_sem_crp_list__{li}"] = _arr(sl["prob"].values) + + li_idx = ["subject", "session", "list"] + dsub = pb.pd_dist_fact_list_sub(df, sim_columns=fc, list_index=li_idx) + cases[f"pd_dist_fact_list_sub__{li}"] = _arr(dsub["dist_fact"].values) + ssub = pb.pd_sem_crp_list_sub(df, sim_columns=fc, bins=bins, list_index=li_idx) + cases[f"pd_sem_crp_list_sub__{li}"] = _arr(ssub["prob"].values) + + # --- Loftus-Masson / Cousineau CI helpers ------------------------------- + rng = np.random.default_rng(7) + mat = rng.normal(size=(10, 4)) + np.arange(4) + cases["lm_equal_kahana"] = _arr(pb.loftus_masson_equal_variance_kahana(mat)) + + long = make_experiment(seed=3)["events"].query("type == 'REC_WORD'").copy() + long["val"] = rng.normal(size=len(long)) + lm = pb.loftus_masson_analytic(long, "subject", "list", "val") + cases["lm_analytic_unequal"] = _arr(lm["CI_unequal"].values) + cases["lm_analytic_equal"] = _arr(lm["CI_equal"].values) + cous = pb.cousineau(long, "subject", "list", "val") + cases["cousineau_adj"] = _arr(cous["adj_val"].values) + cases["cousineau_cmo"] = _arr(cous["cmo_adj_val"].values) + + return cases diff --git a/tests/regression/golden.npz b/tests/regression/golden.npz new file mode 100644 index 0000000000000000000000000000000000000000..fd186749bb2c5b423c05f0566818efc34f7bf177 GIT binary patch literal 85530 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 vNru#|+ROZrWstsIh*{TsyH1B+Zx NameError.""" + import sys + sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) + import pybeh_pd as pb + with pytest.raises(NameError): + pb.loftus_masson_unequal_variance_kahana(np.ones((4, 3))) From 598d3cddc8c9b4146b45bff6fb0e3a96f2dc81a0 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 01:23:39 +0000 Subject: [PATCH 06/15] test: add comprehensive per-function unit tests (Phase 5) Hand-coded value tests, mathematical-property tests, and edge cases for all 29 functions, layered on the Phase 4 behavior lock. 114 new tests (193 total), passing on numpy 1.24 and numpy 2.4. Known-broken behaviors pinned with pins_bug markers. Surfaced two new bugs (reported, not fixed): operator-precedence NaN-padding misclassification in make_recalls_matrix/make_poss_recalls_matrix, and ZeroDivisionError in cousineau for a single condition. --- pytest.ini | 10 + tests/test_ci.py | 330 +++++++++++++++++++++++ tests/test_clustering.py | 439 ++++++++++++++++++++++++++++++ tests/test_crp.py | 569 +++++++++++++++++++++++++++++++++++++++ tests/test_matrix.py | 451 +++++++++++++++++++++++++++++++ 5 files changed, 1799 insertions(+) create mode 100644 pytest.ini create mode 100644 tests/test_ci.py create mode 100644 tests/test_clustering.py create mode 100644 tests/test_crp.py create mode 100644 tests/test_matrix.py diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..304f129 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,10 @@ +[pytest] +testpaths = tests +markers = + hand_coded: concrete input -> hand-verified expected output + property: mathematical property (bounds, symmetry, identity, consistency) + edge_case: inputs that could silently invalidate results + consistency: cross-function / large-sample agreement + regression: golden-master behavior lock + integration: end-to-end pipeline on synthetic or real data + pins_bug: pins CURRENT (known-buggy) behavior; see bug_report.md diff --git a/tests/test_ci.py b/tests/test_ci.py new file mode 100644 index 0000000..1df7257 --- /dev/null +++ b/tests/test_ci.py @@ -0,0 +1,330 @@ +"""Skeptical unit tests for the within-subject confidence-interval helpers in +``pybeh_pd``: ``loftus_masson_analytic``, ``cousineau``, +``loftus_masson_equal_variance_kahana`` and ``loftus_masson_unequal_variance_kahana``. + +These are ports of ``LoftusMasson.m`` (Loftus & Masson, 1994, PB&R) and the +Cousineau-Morey-O'Brien within-subject normalization. + +Tests only PIN current behavior; source is never modified. Known/discovered bugs +are pinned with ``@pytest.mark.pins_bug`` and a comment, and reported back to the +caller. +""" +import math +import warnings + +import numpy as np +import pandas as pd +import pytest +import scipy as sp +from scipy import stats + +import pybeh_pd as pb + + +# --------------------------------------------------------------------------- +# Shared hand-computed fixture: 3 subjects x 2 conditions. +# +# dat = [[1, 3], +# [2, 5], +# [4, 6]] +# grand mean = 21/6 = 3.5, grand total = 21 +# SS_T = sum((x-3.5)^2) = 6.25+0.25+2.25+2.25+0.25+6.25 = 17.5 +# Srow = [4, 7, 10]; SSrow = (16+49+100)/2 - 21^2/6 = 82.5 - 73.5 = 9.0 +# Scol = [7, 14]; SScol = (49+196)/3 - 73.5 = 81.6667 - 73.5 = 8.16667 +# SSint = 17.5 - 9.0 - 8.16667 = 0.33333 +# df_int = (3*2-1)-(3-1)-(2-1) = 5-2-1 = 2 +# MSint = 0.33333/2 = 0.16667 +# SE = sqrt(0.16667/3) = 0.235702 +# t.975(df=2) = 4.302653 +# CI = 0.235702 * 4.302653 = 1.0141449740863315 (same for both columns) +# --------------------------------------------------------------------------- +DAT_3x2 = np.array([[1.0, 3.0], [2.0, 5.0], [4.0, 6.0]]) +CI_3x2_EQUAL = 1.0141449740863315 + + +def _long_from_matrix(dat, sub_col="sub", cond_col="cond", value_col="val"): + """Reshape a subjects x conditions matrix to a tidy long DataFrame.""" + n_subs, n_conds = dat.shape + rows = [ + {sub_col: s, cond_col: c, value_col: float(dat[s, c])} + for s in range(n_subs) + for c in range(n_conds) + ] + return pd.DataFrame(rows) + + +# =========================================================================== +# 1. HAND-CODED VALUE TESTS +# =========================================================================== + +@pytest.mark.hand_coded +def test_equal_variance_kahana_hand_value(): + """loftus_masson_equal_variance_kahana on the 3x2 fixture matches the + by-hand Loftus-Masson Eq. (2) CI, is constant across conditions, and has + length == n_conditions.""" + ci = pb.loftus_masson_equal_variance_kahana(DAT_3x2) + + # Reconstruct the expected value from hand-computed ANOVA pieces. + SS_int = 0.3333333333333428 # 17.5 - 9.0 - 8.166666... + df_int = 2 + MS_int = SS_int / df_int + crit = sp.stats.t.ppf(0.975, df_int) + expected = np.sqrt(MS_int / 3) * crit + + assert ci.shape == (2,) # one entry per condition + assert np.allclose(ci, expected) + assert np.allclose(ci, CI_3x2_EQUAL) + # equal-variance assumption => identical half-width for every condition + assert ci[0] == ci[1] + + +@pytest.mark.hand_coded +def test_analytic_CI_equal_matches_kahana_same_data(): + """HIGH-VALUE CHECK: loftus_masson_analytic's 'CI_equal' column is a second + implementation of the *same* Loftus-Masson Eq. (2). On identical data it + must agree with loftus_masson_equal_variance_kahana. (They do agree.)""" + df = _long_from_matrix(DAT_3x2) + with warnings.catch_warnings(): + # CI_unequal has a NaN (negative estimator -> sqrt warning) for this + # tiny matrix; irrelevant to the CI_equal comparison. + warnings.simplefilter("ignore", RuntimeWarning) + out = pb.loftus_masson_analytic(df, "sub", "cond", "val") + + ci_kahana = pb.loftus_masson_equal_variance_kahana(DAT_3x2) + + assert list(out.columns) == ["cond", "M_C", "CI_unequal", "CI_equal"] + assert len(out) == 2 + # CI_equal constant across conditions and equal to the hand value. + assert np.allclose(out["CI_equal"].values, CI_3x2_EQUAL) + # The two independent implementations of Eq. (2) agree. + assert np.allclose(out["CI_equal"].values, ci_kahana) + # condition means + assert np.allclose( + sorted(out["M_C"].values), sorted([7 / 3, 14 / 3]) + ) + + +@pytest.mark.hand_coded +def test_analytic_CI_equal_matches_kahana_balanced_random(): + """Same cross-implementation agreement on a larger, well-behaved balanced + design (so CI_unequal is real, not NaN).""" + rng = np.random.default_rng(0) + n, k = 8, 4 + dat = rng.normal(5, 2, (n, k)) + np.arange(k) + df = _long_from_matrix(dat) + + out = pb.loftus_masson_analytic(df, "sub", "cond", "val") + ci_kahana = pb.loftus_masson_equal_variance_kahana(dat) + + assert len(out) == k + assert np.allclose(out["CI_equal"].values, ci_kahana) + assert (out["CI_unequal"] >= 0).all() + + +@pytest.mark.hand_coded +def test_cousineau_adj_and_cmo_hand_values(): + """cousineau: + adj_ = v + grand_mean - subject_mean (exact) + cmo_adj_ = sqrt(K/(K-1))*(v - subject_mean) + grand_mean (K=n_conds) + Hand-checked on the 3x2 fixture (grand mean 3.5, K=2).""" + df = _long_from_matrix(DAT_3x2) + out = pb.cousineau(df, "sub", "cond", "val") + + grand = 3.5 + # subject means: sub0 -> (1+3)/2=2.0, sub1 -> (2+5)/2=3.5, sub2 -> (4+6)/2=5.0 + sub_means = {0: 2.0, 1: 3.5, 2: 5.0} + K = 2 + factor = math.sqrt(K / (K - 1)) + + for _, r in out.iterrows(): + sm = sub_means[r["sub"]] + exp_adj = r["val"] + grand - sm + exp_cmo = factor * (r["val"] - sm) + grand + assert r["adj_val"] == pytest.approx(exp_adj) + assert r["cmo_adj_val"] == pytest.approx(exp_cmo) + + # spot-check the exact emitted values (regression-grade) + row0 = out[(out["sub"] == 0) & (out["cond"] == 0)].iloc[0] + assert row0["adj_val"] == pytest.approx(2.5) + assert row0["cmo_adj_val"] == pytest.approx(math.sqrt(2) * (1.0 - 2.0) + 3.5) + + # required output columns are present + for col in ["M", "M_S", "adj_val", "cmo_adj_val"]: + assert col in out.columns + + +@pytest.mark.hand_coded +def test_cousineau_within_cols_path_hand_values(): + """The within_cols branch groups the grand mean M by within_cols and the + subject mean M_S by (sub_cols + within_cols). Hand-checked. + + Design: 2 subjects x 2 conds x 2 within-levels, val = sub*10 + cond + wc. + For wc=0 group values are {0,1,10,11} -> M=5.5; sub0/wc0 subject mean is + mean(0,1)=0.5; so adj for (sub0,cond0,wc0,val=0) = 0 + 5.5 - 0.5 = 5.0. + """ + rows = [ + {"sub": s, "cond": c, "wc": w, "val": float(s * 10 + c + w)} + for s in range(2) + for c in range(2) + for w in range(2) + ] + df = pd.DataFrame(rows) + out = pb.cousineau(df, "sub", "cond", "val", within_cols=["wc"]) + + r0 = out[(out["sub"] == 0) & (out["cond"] == 0) & (out["wc"] == 0)].iloc[0] + assert r0["M"] == pytest.approx(5.5) + assert r0["M_S"] == pytest.approx(0.5) + assert r0["adj_val"] == pytest.approx(5.0) + + # adj is val + (within-group grand mean) - (within-subject mean) throughout + expected_adj = df["val"].values + out["M"].values - out["M_S"].values + assert np.allclose(out["adj_val"].values, expected_adj) + + +# =========================================================================== +# 2. MATHEMATICAL PROPERTIES +# =========================================================================== + +@pytest.mark.property +def test_cousineau_removes_between_subject_variance(): + """Cousineau normalization: the per-subject mean of adj_ is constant + across subjects (between-subject variance removed).""" + rng = np.random.default_rng(7) + n, k = 6, 3 + # add large per-subject offsets so between-subject variance dominates + dat = rng.normal(0, 1, (n, k)) + (np.arange(n) * 100)[:, None] + df = _long_from_matrix(dat) + out = pb.cousineau(df, "sub", "cond", "val") + + per_sub = out.groupby("sub")["adj_val"].mean().values + assert np.allclose(per_sub, per_sub[0]) + # and it equals the grand mean + assert per_sub[0] == pytest.approx(df["val"].mean()) + + +@pytest.mark.property +def test_cmo_preserves_grand_mean(): + """The Cousineau-Morey-O'Brien adjustment preserves the grand mean.""" + rng = np.random.default_rng(11) + n, k = 5, 4 + dat = rng.normal(3, 2, (n, k)) + np.arange(k) + df = _long_from_matrix(dat) + out = pb.cousineau(df, "sub", "cond", "val") + assert out["cmo_adj_val"].mean() == pytest.approx(df["val"].mean()) + + +@pytest.mark.property +def test_equal_variance_basic_properties(): + """loftus_masson_equal_variance_kahana: non-negative, all entries equal, + length == n_conditions.""" + rng = np.random.default_rng(3) + for n, k in [(4, 2), (6, 3), (10, 5)]: + dat = rng.normal(0, 1, (n, k)) + ci = pb.loftus_masson_equal_variance_kahana(dat) + assert ci.shape == (k,) + assert np.all(ci >= 0) + assert np.allclose(ci, ci[0]) + + +@pytest.mark.property +def test_equal_variance_shrinks_with_more_subjects(): + """Adding subjects (replicating the design) shrinks the CI. + + NOTE: the rubric's '~1/sqrt(2)' expectation does NOT hold exactly for this + estimator, and we deliberately do NOT assert it. Replicating the rows keeps + SS_int proportional but df_int = (n-1)(k-1) more-than-doubles when n -> 2n, + so both MS_int and the t-criterion change. The robust, true property is that + the CI strictly shrinks. (Measured ratio ~0.378, not 0.707, for the 3x2 + fixture -- reported as a methodological note, not a code bug.)""" + dat = DAT_3x2 + ci_n = pb.loftus_masson_equal_variance_kahana(dat)[0] + ci_2n = pb.loftus_masson_equal_variance_kahana(np.vstack([dat, dat]))[0] + ci_3n = pb.loftus_masson_equal_variance_kahana(np.vstack([dat, dat, dat]))[0] + + assert ci_2n < ci_n + assert ci_3n < ci_2n + assert ci_3n > 0 + + # The *SE* part alone (sqrt(MS_int/n)) is what the 1/sqrt(n) intuition refers + # to; pin that it too fails to scale as 1/sqrt(2) here because MS_int is not + # replication-invariant (df grows). + assert not np.isclose(ci_2n / ci_n, 1 / math.sqrt(2), atol=0.05) + + +@pytest.mark.property +def test_analytic_shape_and_signs(): + """loftus_masson_analytic returns one row per condition; CI_equal is + constant across conditions; CI_unequal >= 0 on well-behaved data.""" + rng = np.random.default_rng(5) + n, k = 12, 4 + dat = rng.normal(5, 1.5, (n, k)) + np.arange(k) + df = _long_from_matrix(dat) + out = pb.loftus_masson_analytic(df, "sub", "cond", "val") + + assert len(out) == k + assert out["cond"].nunique() == k + assert np.allclose(out["CI_equal"].values, out["CI_equal"].iloc[0]) + assert (out["CI_unequal"] >= 0).all() + assert (out["CI_equal"] >= 0).all() + + +# =========================================================================== +# 3. EDGE CASES +# =========================================================================== + +@pytest.mark.edge_case +@pytest.mark.pins_bug +def test_cousineau_single_condition_raises_zerodivision(): + """EDGE/BUG: with a single condition (K=1) the CMO factor is + sqrt(K/(K-1)) = sqrt(1/0). Because n_conds is a Python int from + DataFrame.nunique(), '1/0' is a *Python* division and raises + ZeroDivisionError (not inf/nan). Pinned as current behavior. + + Source: pybeh_pd.py:818-819 (cousineau). + """ + df = pd.DataFrame( + [{"sub": s, "cond": 0, "val": float(s)} for s in range(3)] + ) + with pytest.raises(ZeroDivisionError): + pb.cousineau(df, "sub", "cond", "val") + + +@pytest.mark.edge_case +def test_cousineau_single_subject(): + """Single subject: M_S equals each value within the (only) subject, so the + Cousineau adj reduces to the condition value (adj = v + grand - subj_mean, + with subj_mean == grand here only if balanced).""" + df = pd.DataFrame( + [{"sub": 0, "cond": c, "val": float(c + 1)} for c in range(3)] + ) + out = pb.cousineau(df, "sub", "cond", "val") + grand = df["val"].mean() # = 2.0 + # one subject => M_S == grand mean for every row + assert np.allclose(out["M_S"].values, grand) + # therefore adj == original value + assert np.allclose(out["adj_val"].values, df["val"].values) + + +@pytest.mark.edge_case +def test_equal_variance_single_subject_is_nan(): + """Single subject (1 x k): df_int = (1*k-1)-(1-1)-(k-1) = 0, so MS_int and + the CI are undefined. Pin current behavior: returns NaNs.""" + with warnings.catch_warnings(): + warnings.simplefilter("ignore", RuntimeWarning) + ci = pb.loftus_masson_equal_variance_kahana(np.array([[1.0, 2.0]])) + assert ci.shape == (2,) + assert np.all(np.isnan(ci)) + + +@pytest.mark.edge_case +@pytest.mark.pins_bug +def test_unequal_variance_kahana_raises_nameerror(): + """KNOWN BUG B1: loftus_masson_unequal_variance_kahana's first statement is + `dat = mat`, referencing an undefined global `mat`, so EVERY call raises + NameError before any computation. Pinned. + + Source: pybeh_pd.py:852 (`dat = mat`). + """ + for d in (DAT_3x2, np.ones((4, 3)), np.array([[1.0, 2.0, 3.0]])): + with pytest.raises(NameError): + pb.loftus_masson_unequal_variance_kahana(d) diff --git a/tests/test_clustering.py b/tests/test_clustering.py new file mode 100644 index 0000000..f86b997 --- /dev/null +++ b/tests/test_clustering.py @@ -0,0 +1,439 @@ +"""Skeptical unit tests for the clustering-factor family in ``pybeh_pd``. + +Covered functions +----------------- +- ``temp_percentile_rank`` / ``dist_percentile_rank`` (from ``pybeh_copy``) +- ``temp_fact`` (from ``pybeh_copy``) +- ``min_temp_fact`` (3D repeated-pres path) +- ``dist_fact`` +- ``pd_temp_fact`` / ``pd_min_temp_fact`` / ``pd_dist_fact`` +- ``pd_dist_fact_list`` / ``pd_dist_fact_list_sub`` + +Behavior-preservation rules: where the math disagrees with the code, or a code +path raises, the test PINS the current behavior (``@pytest.mark.pins_bug``) and +the divergence is reported separately -- nothing in the source is changed. + +Numpy note: this repo runs on numpy 1.24 (numpy1). The percentile helpers are +invoked internally with numpy scalars + numpy arrays; the tests mirror that +(passing ``np.int64`` / ``np.float64`` scalars) both to match real call sites +and to avoid the numpy-2 0-d ``nonzero`` path (known bug B5), which would only +fire under numpy>=2. +""" +from __future__ import annotations + +import os +import sys +import warnings + +# Make the top-level ``pybeh_pd.py`` module win over the same-named source +# directory (a namespace-package shadow exists because the repo dir is itself +# called ``pybeh_pd``). Inserting the repo root first mirrors the regression +# harness (tests/regression/cases.py) and resolves to the real module file. +_HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.join(_HERE, "..")) # repo root (contains pybeh_pd.py) + +import numpy as np # noqa: E402 +import pytest # noqa: E402 + +import pybeh_pd as pb # noqa: E402 +from factories import make_experiment # noqa: E402 + +# The module must be the real file, not the namespace-package shadow. +assert pb.__file__ is not None and pb.__file__.endswith("pybeh_pd.py"), pb.__file__ + + +# Several pandas wrappers emit SettingWithCopyWarning / FutureWarning that are +# orthogonal to the math under test. +pytestmark = pytest.mark.filterwarnings("ignore::FutureWarning") + + +# --------------------------------------------------------------------------- +# 1. HAND-CODED VALUE TESTS +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_temp_percentile_rank_hand(): + # possible sorted DESC = [3, 2, 1]; actual=1 is the smallest distance -> + # it occupies rank index 2 of 3 -> 2 / (3-1) = 1.0 (max clustering). + assert pb.temp_percentile_rank(np.int64(1), np.array([3, 2, 1])) == 1.0 + # actual=3 is the largest distance -> index 0 -> 0 / 2 = 0.0 (anti-cluster). + assert pb.temp_percentile_rank(np.int64(3), np.array([3, 2, 1])) == 0.0 + # actual=2 is the median -> index 1 -> 1 / 2 = 0.5 (chance). + assert pb.temp_percentile_rank(np.int64(2), np.array([3, 2, 1])) == 0.5 + + +@pytest.mark.hand_coded +def test_temp_percentile_rank_ties_and_none(): + # Ties: sorted DESC [3, 3, 1]; actual=3 matches indices 0 and 1 -> + # mean(0,1)=0.5 -> 0.5 / (3-1) = 0.25. + assert pb.temp_percentile_rank(np.int64(3), np.array([3, 3, 1])) == 0.25 + # No match -> None. + assert pb.temp_percentile_rank(np.int64(5), np.array([3, 2, 1])) is None + # Fewer than 2 possibles -> None. + assert pb.temp_percentile_rank(np.int64(1), np.array([1])) is None + # Exactly 0 possibles -> None. + assert pb.temp_percentile_rank(np.int64(1), np.array([])) is None + + +@pytest.mark.hand_coded +def test_dist_percentile_rank_is_similarity_flips_sort(): + poss = np.array([0.1, 0.5, 0.9]) + # Distance mode: sorted DESC [0.9, 0.5, 0.1]. actual=0.1 (smallest distance, + # i.e. closest) -> index 2 -> 2/2 = 1.0. + assert pb.dist_percentile_rank(np.float64(0.1), poss) == 1.0 + # Largest distance -> index 0 -> 0.0. + assert pb.dist_percentile_rank(np.float64(0.9), poss) == 0.0 + # Median -> 0.5. + assert pb.dist_percentile_rank(np.float64(0.5), poss) == 0.5 + # Similarity mode flips the sort to ASC [0.1, 0.5, 0.9]; actual=0.1 (lowest + # similarity -> most distant) -> index 0 -> 0.0. + assert pb.dist_percentile_rank(np.float64(0.1), poss, is_similarity=True) == 0.0 + # Highest similarity -> index 2 -> 1.0. + assert pb.dist_percentile_rank(np.float64(0.9), poss, is_similarity=True) == 1.0 + + +@pytest.mark.hand_coded +def test_temp_fact_perfect_and_anticlustered(): + # Perfectly clustered recall (adjacent serial positions) -> factor 1.0. + assert pb.temp_fact(recalls=np.array([[1, 2, 3, 4]]), + subjects=["_"], listLength=4)[0] == 1.0 + # Recall [1,4,2,3]: each made transition is the *largest* available -> + # 1->4: poss |i-1| for i in {2,3,4} = {1,2,3}; actual=3 -> 0.0 + # 4->2: poss |i-4| for i in {2,3} = {2,1}; actual=2 -> 0.0 + # 2->3: only one possible -> None (skipped) + # mean = 0.0. + assert pb.temp_fact(recalls=np.array([[1, 4, 2, 3]]), + subjects=["_"], listLength=4)[0] == 0.0 + + +@pytest.mark.hand_coded +def test_temp_fact_partial_by_hand(): + # Recall [2,1,3] on listLength 4, fully worked out: + # 2->1: seen={2}; poss |i-2| for i in {1,3,4} = {1,1,2}; actual=1 -> + # sorted DESC [2,1,1], matches idx 1,2 -> mean 1.5 / 2 = 0.75 + # 1->3: seen={2,1}; poss |i-1| for i in {3,4} = {2,3}; actual=2 -> + # sorted DESC [3,2], match idx 1 -> 1/1 = 1.0 + # mean = (0.75 + 1.0) / 2 = 0.875. + got = pb.temp_fact(recalls=np.array([[2, 1, 3, 0]]), + subjects=["_"], listLength=4)[0] + assert got == pytest.approx(0.875) + + +@pytest.mark.hand_coded +def test_dist_fact_hand_and_similarity_flip(): + dist = np.array([[0., 1., 2.], [1., 0., 1.], [2., 1., 0.]]) + pres = np.array([[1, 2, 3]]) + # Recall 1->2 (the closest neighbour). poss dist from item1 to {2,3} = + # [1, 2]; actual = 1 -> sorted DESC [2,1] match idx 1 -> 1.0 (max + # distance-clustering for the *shortest* hop). + rec = np.array([[1, 2, 0]]) + assert pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=dist)[0] == 1.0 + # Flipping is_similarity on the same matrix sends a short hop to the + # opposite end -> 0.0. + assert pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, subjects=["_"], + dist_mat=dist, is_similarity=True)[0] == 0.0 + + +# --------------------------------------------------------------------------- +# 2. MATHEMATICAL PROPERTIES +# --------------------------------------------------------------------------- + +def _in_unit_or_nan(x): + x = float(x) + return np.isnan(x) or (0.0 - 1e-12 <= x <= 1.0 + 1e-12) + + +@pytest.mark.property +def test_temp_fact_in_unit_interval(): + for seed in range(6): + ex = make_experiment(seed=seed) + recalls = pb.make_recalls_matrix(ex["pres_itemnos"], ex["rec_itemnos"]) + vals = pb.temp_fact(recalls=recalls, + subjects=["_"] * recalls.shape[0], + listLength=ex["list_length"]) + assert all(_in_unit_or_nan(v) for v in vals) + + +@pytest.mark.property +def test_dist_fact_in_unit_interval(): + for seed in range(6): + ex = make_experiment(seed=seed) + sims = pb.get_sim_mat(ex["events"], ex["feat_cols"]) + recalls = pb.make_recalls_matrix(ex["pres_itemnos"], ex["rec_itemnos"]) + # get_sim_mat returns Euclidean *distances* -> is_similarity defaults + # to False, which is correct here. Diagonal is 0, so the B2 warning + # heuristic is not tripped. + vals = pb.dist_fact(rec_itemnos=ex["rec_itemnos"], + pres_itemnos=ex["pres_itemnos"], + subjects=["_"] * recalls.shape[0], dist_mat=sims) + assert all(_in_unit_or_nan(v) for v in vals) + + +@pytest.mark.property +def test_dist_fact_random_matrices_stay_in_unit(): + rng = np.random.default_rng(7) + for _ in range(30): + d = rng.random((8, 8)) + d = (d + d.T) / 2.0 + np.fill_diagonal(d, 0.0) + pres = np.array([np.arange(1, 9)]) + rec = np.zeros((1, 8), dtype=int) + rec[0, :5] = rng.permutation(np.arange(1, 9))[:5] + v = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=d)[0] + assert _in_unit_or_nan(v) + + +@pytest.mark.property +def test_min_temp_fact_3d_in_unit_interval(): + # Repeated-presentation case (item 2 presented twice). max_n_reps=2 path. + pres = np.array([[1, 2, 3, 4, 2], [1, 2, 3, 4, 2]]) + rec = np.array([[2, 4, 1, 3, 0], [3, 1, 4, 2, 0]]) + recalls3d = pb.make_recalls_matrix(pres, rec, max_n_reps=2) + poss3d = pb.make_poss_recalls_matrix(pres, max_n_reps=2) + vals = pb.min_temp_fact(recalls=recalls3d, poss_recalls=poss3d, + subjects=["_", "_"], listLength=5) + assert all(_in_unit_or_nan(v) for v in vals) + + +@pytest.mark.property +def test_pd_temp_fact_and_pd_dist_fact_in_unit_interval(): + for seed in range(4): + ex = make_experiment(seed=seed) + df, fc = ex["events"], ex["feat_cols"] + assert _in_unit_or_nan(pb.pd_temp_fact(df)) + assert _in_unit_or_nan(pb.pd_dist_fact(df, sim_columns=fc)) + + +@pytest.mark.property +def test_percentile_rank_always_in_unit_or_none(): + rng = np.random.default_rng(11) + for _ in range(200): + poss = rng.integers(0, 6, size=rng.integers(0, 6)) + # actual drawn from the possible set or an out-of-range value. + if len(poss) and rng.random() < 0.7: + actual = np.int64(rng.choice(poss)) + else: + actual = np.int64(99) + r = pb.temp_percentile_rank(actual, poss) + assert r is None or _in_unit_or_nan(r) + if len(poss) < 2: + assert r is None + + +@pytest.mark.property +def test_dist_fact_is_similarity_direction_on_hand_example(): + # On the SAME distance matrix, the shortest hop scores high in distance + # mode (clustering) and low in similarity mode -- opposite ends. + dist = np.array([[0., 1., 2.], [1., 0., 1.], [2., 1., 0.]]) + pres = np.array([[1, 2, 3]]) + rec = np.array([[1, 2, 0]]) # closest possible hop + f = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=dist, is_similarity=False)[0] + t = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=dist, is_similarity=True)[0] + assert f == 1.0 and t == 0.0 + # With a single binary transition (no ties), the two modes are + # complementary. + assert f + t == pytest.approx(1.0) + + +@pytest.mark.property +def test_dist_fact_negated_distance_matches_similarity_flag(): + # is_similarity=True on a distance matrix should equal is_similarity=False + # on (max - distance), provided we reset the diagonal so the B2 heuristic + # (large diagonal => warn) does not fire. + dist = np.array([[0., 1., 2., 3.], + [1., 0., 1., 2.], + [2., 1., 0., 1.], + [3., 2., 1., 0.]]) + pres = np.array([[1, 2, 3, 4]]) + rec = np.array([[1, 3, 2, 0]]) + negdist = dist.max() - dist + np.fill_diagonal(negdist, 0.0) + a = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, subjects=["_"], + dist_mat=dist, is_similarity=True)[0] + b = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, subjects=["_"], + dist_mat=negdist, is_similarity=False)[0] + assert a == pytest.approx(b) + + +@pytest.mark.pins_bug +def test_dist_fact_diagonal_heavy_matrix_raises_nameerror_B2(): + # KNOWN BUG B2: dist_fact() calls warnings.warn(...) but ``warnings`` is + # never imported (pybeh_pd.py:640). A similarity-looking matrix (large + # diagonal) with is_similarity=False reaches that branch and raises + # NameError instead of warning. Pin the current behavior. + diag_heavy = np.array([[10., 0., 0.], [0., 10., 0.], [0., 0., 10.]]) + pres = np.array([[1, 2, 3]]) + rec = np.array([[1, 2, 0]]) + with pytest.raises(NameError): + pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=diag_heavy, is_similarity=False) + + +@pytest.mark.pins_bug +def test_dist_fact_diagonal_heavy_ok_when_is_similarity_true(): + # The same diagonal-heavy matrix does NOT raise when is_similarity=True, + # because that branch is guarded by ``not is_similarity``. Confirms the B2 + # trigger is specifically the (diagonal-heavy AND is_similarity=False) + # combination, and that a similarity matrix is handled normally otherwise. + diag_heavy = np.array([[10., 1., 2.], [1., 10., 1.], [2., 1., 10.]]) + pres = np.array([[1, 2, 3]]) + rec = np.array([[1, 2, 0]]) + v = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=diag_heavy, is_similarity=True)[0] + assert _in_unit_or_nan(v) + + +@pytest.mark.property +def test_temp_fact_random_recalls_average_near_chance(): + # Statistical consistency: uniformly random full recall orders should give + # a temporal factor that averages to ~0.5 (chance). Use one subject with + # many trials and assert the aggregate lands in a loose chance band. + rng = np.random.default_rng(42) + ll, n_trials = 10, 400 + recalls = np.stack([rng.permutation(np.arange(1, ll + 1)) + for _ in range(n_trials)]) + val = pb.temp_fact(recalls=recalls, + subjects=["_"] * n_trials, listLength=ll)[0] + assert 0.3 <= val <= 0.7 + # Tighter sanity: this seed is deterministic and very close to 0.5. + assert val == pytest.approx(0.5, abs=0.05) + + +# --------------------------------------------------------------------------- +# 3. EDGE CASES +# --------------------------------------------------------------------------- + +@pytest.mark.edge_case +def test_temp_fact_empty_and_single_recall_nan(): + # No recalls at all -> NaN (count stays 0 -> 0/0). + assert np.isnan(pb.temp_fact(recalls=np.array([[0, 0, 0, 0]]), + subjects=["_"], listLength=4)[0]) + # A single recall -> no transition possible -> NaN. + assert np.isnan(pb.temp_fact(recalls=np.array([[1, 0, 0, 0]]), + subjects=["_"], listLength=4)[0]) + + +@pytest.mark.edge_case +def test_temp_fact_all_intrusions_nan(): + # All extra-list intrusions (-1) -> no clean transitions -> NaN. + assert np.isnan(pb.temp_fact(recalls=np.array([[-1, -1, -1, -1]]), + subjects=["_"], listLength=4)[0]) + + +@pytest.mark.edge_case +def test_dist_fact_empty_and_single_recall_nan(): + dist = np.array([[0., 1., 2.], [1., 0., 1.], [2., 1., 0.]]) + pres = np.array([[1, 2, 3]]) + assert np.isnan(pb.dist_fact(rec_itemnos=np.array([[0, 0, 0]]), + pres_itemnos=pres, subjects=["_"], + dist_mat=dist)[0]) + assert np.isnan(pb.dist_fact(rec_itemnos=np.array([[1, 0, 0]]), + pres_itemnos=pres, subjects=["_"], + dist_mat=dist)[0]) + + +@pytest.mark.edge_case +def test_dist_fact_ret_counts_shape(): + dist = np.array([[0., 1., 2.], [1., 0., 1.], [2., 1., 0.]]) + pres = np.array([[1, 2, 3]]) + rec = np.array([[1, 2, 0]]) + final, total, count = pb.dist_fact(rec_itemnos=rec, pres_itemnos=pres, + subjects=["_"], dist_mat=dist, + ret_counts=True) + assert final[0] == 1.0 + assert total[0] == 1.0 + assert count[0] == 1.0 + + +@pytest.mark.pins_bug +def test_pd_min_temp_fact_default_raises_indexerror_B4(): + # KNOWN BUG B4: pd_min_temp_fact() defaults max_n_reps=1, which makes + # make_poss_recalls_matrix squeeze to 2D; min_temp_fact then indexes + # serialpos[0] on a scalar -> IndexError. Pin the raise. + ex = make_experiment(seed=0) + with pytest.raises(IndexError): + pb.pd_min_temp_fact(ex["events"]) + + +@pytest.mark.edge_case +def test_pd_min_temp_fact_max_n_reps_2_returns_unit_float(): + ex = make_experiment(seed=0) + val = pb.pd_min_temp_fact(ex["events"], max_n_reps=2) + assert isinstance(val, float) + assert _in_unit_or_nan(val) + + +@pytest.mark.edge_case +def test_pd_dist_fact_no_presentations_returns_nan(): + # A subject DataFrame with no WORD/REC_WORD rows (only WORD_VALS) yields an + # empty presentation matrix -> pres_itemnos.shape[1] == 0 -> np.nan. + ex = make_experiment(seed=0) + only_vals = ex["events"].query("type == 'WORD_VALS'").copy() + assert np.isnan(pb.pd_dist_fact(only_vals, sim_columns=ex["feat_cols"])) + + +@pytest.mark.edge_case +def test_pd_dist_fact_list_one_list(): + # pd_dist_fact_list reads features off the WORD rows of a single list and + # returns a one-row frame with dist_fact/total/count; dist_fact in [0,1]. + ex = make_experiment(seed=0) + list0 = ex["events"].query("list == 0") + out = pb.pd_dist_fact_list(list0, sim_columns=ex["feat_cols"]) + assert list(out.columns) == ["dist_fact", "total", "count"] + assert len(out) == 1 + assert _in_unit_or_nan(out["dist_fact"].iloc[0]) + # count is the number of scored transitions; total/count == dist_fact. + c = out["count"].iloc[0] + if c > 0: + assert out["dist_fact"].iloc[0] == pytest.approx( + out["total"].iloc[0] / c) + + +@pytest.mark.edge_case +def test_pd_dist_fact_list_sub_aggregates_to_unit(): + # Aggregate across this subject's lists. Default list_index uses 'trial'; + # the factory uses 'list', so pass list_index explicitly (per the harness). + ex = make_experiment(seed=0) + df = ex["events"].query("type != 'WORD_VALS'").copy() + out = pb.pd_dist_fact_list_sub( + df, sim_columns=ex["feat_cols"], + list_index=["subject", "session", "list"]) + assert "dist_fact" in out.columns + assert len(out) == 1 + assert _in_unit_or_nan(out["dist_fact"].iloc[0]) + # Subject-level factor is the transition-weighted pool of all lists. + assert out["dist_fact"].iloc[0] == pytest.approx( + out["total"].iloc[0] / out["count"].iloc[0]) + + +# --------------------------------------------------------------------------- +# Scrutiny: does temp_fact handle the seen-set across repeated serial positions? +# --------------------------------------------------------------------------- + +@pytest.mark.property +def test_temp_fact_repeat_recall_severs_transition_chain(): + # Scrutiny of the seen-set / clean-mask interaction across a repeated serial + # position. For [2,2,1] the clean mask is [1,0,1]: the *repeated* '2' is + # masked at position 1. A transition is scored only when BOTH the current + # and next positions are clean, so: + # j=0 (2->2): mask[1]=0 -> not scored + # j=1 (2->1): mask[1]=0 -> not scored + # The repeat therefore severs the chain on BOTH sides and NO transition is + # counted -> NaN. (It does NOT silently collapse to the plain [2,1] case.) + assert np.isnan(pb.temp_fact(recalls=np.array([[2, 2, 1, 0]]), + subjects=["_"], listLength=3)[0]) + # By contrast the un-repeated [2,1] scores a single clean transition: + # 2->1 on LL=3: seen={2}; poss |i-2| for i in {1,3} = {1,1}; actual=1 -> + # sorted DESC [1,1] matches idx 0,1 -> mean 0.5 / 1 = 0.5. + assert pb.temp_fact(recalls=np.array([[2, 1, 0, 0]]), + subjects=["_"], listLength=3)[0] == pytest.approx(0.5) + # A repeat that does NOT sit between the two scored items leaves a later + # clean transition intact: [1,2,1,3] -> mask [1,1,0,1]; only the 1->2 + # transition (positions 0,1) is scored. seen={1}; poss |i-1| for i in {2,3} + # = {1,2}; actual=1 -> sorted DESC [2,1] match idx1 -> 1.0. + assert pb.temp_fact(recalls=np.array([[1, 2, 1, 3]]), + subjects=["_"], listLength=3)[0] == pytest.approx(1.0) diff --git a/tests/test_crp.py b/tests/test_crp.py new file mode 100644 index 0000000..2bb3202 --- /dev/null +++ b/tests/test_crp.py @@ -0,0 +1,569 @@ +"""Skeptical unit tests for the lag-CRP / sem-CRP family in pybeh_pd. + +Covers (importable as ``pb.``): + crp, min_crp, sem_crp, pd_crp, pd_min_crp, pd_sem_crp, + pd_sem_crp_list, pd_sem_crp_list_sub, and the helper + make_poss_recalls_matrix / make_recalls_matrix used to build inputs. + +Rules: tests only; current behavior is pinned, not "fixed". Where the math +deviates from the code, a ``pins_bug`` marker + comment explains why. +""" +from __future__ import annotations + +import warnings + +import numpy as np +import pandas as pd +import pytest +from scipy.spatial import distance_matrix + +import pybeh_pd as pb +from pybeh_pd import ( + crp, + min_crp, + sem_crp, + make_recalls_matrix, + make_poss_recalls_matrix, +) +from factories import make_experiment + + +# --------------------------------------------------------------------------- +# helpers +# --------------------------------------------------------------------------- +def _in_unit_or_nan(a): + """True iff every element is NaN or within [0, 1].""" + a = np.asarray(a, dtype=float) + finite = a[~np.isnan(a)] + return np.all((finite >= 0.0) & (finite <= 1.0)) + + +def _matrices_no_repeats(seed): + """Build (pres, rec, recalls) matrices with no repeated presentations.""" + exp = make_experiment(n_lists=6, list_length=8, p_intrusion=0.0, seed=seed) + pres = exp["pres_itemnos"] + rec = exp["rec_itemnos"] + recalls = make_recalls_matrix(pres, rec) + return pres, rec, recalls, exp + + +# =========================================================================== +# crp (pybeh_copy lag-CRP) +# =========================================================================== +@pytest.mark.hand_coded +def test_crp_forward_recall_all_plus_one(): + # Perfect forward recall [1,2,3,4]: every transition is +1. + # listLength=4, lag_num=3 -> width 2*3+1 = 7, center (lag 0) NaN. + out = crp(recalls=np.array([[1, 2, 3, 4]]), subjects=["a"], + listLength=4, lag_num=3) + assert out.shape == (1, 7) + # columns map to lags -3..+3; center index 3 is lag 0 and MUST be NaN. + assert np.isnan(out[0, 3]) + # Hand accounting (already-recalled lower positions are NOT possible): + # 1->2: from sp1, poss lags {+1,+2,+3}, actual +1 + # 2->3: from sp2 seen{1,2}, poss lags {+1,+2}, actual +1 + # 3->4: from sp3 seen{1,2,3}, poss lags {+1}, actual +1 + # lag +1 (index 4): actual 3 / poss 3 = 1.0 + assert out[0, 4] == 1.0 + # lag +2 (index 5): actual 0 / poss 2 = 0.0; lag +3 (index 6): 0/1 = 0.0 + assert out[0, 5] == 0.0 + assert out[0, 6] == 0.0 + # negative lags were never possible (lower sps already recalled) -> NaN + assert np.isnan(out[0, 2]) # lag -1 + assert np.isnan(out[0, 1]) # lag -2 + assert np.isnan(out[0, 0]) # lag -3 + + +@pytest.mark.hand_coded +def test_crp_single_transition(): + # Only one valid transition 2->3 (then padding zeros). + # listLength=4, lag_num=3. Transition is +1. + out = crp(recalls=np.array([[2, 3, 0, 0]]), subjects=["a"], + listLength=4, lag_num=3) + assert out.shape == (1, 7) + assert np.isnan(out[0, 3]) # center NaN + # From sp 2, possible lags with sp not yet seen: {-1, +1, +2}; actual +1. + # lag +1 idx4 -> 1/1 = 1.0; lag -1 idx2 -> 0/1 = 0.0; lag +2 idx5 -> 0/1. + assert out[0, 4] == 1.0 + assert out[0, 2] == 0.0 + assert out[0, 5] == 0.0 + # lags with no possible transition stay NaN (e.g. +3 idx6, -2 idx1, -3 idx0) + assert np.isnan(out[0, 6]) + assert np.isnan(out[0, 1]) + assert np.isnan(out[0, 0]) + + +@pytest.mark.hand_coded +def test_crp_backward_then_forward(): + # recalls [2,1,3]: transitions 2->1 (lag -1), 1->3 (lag +2). + # listLength=3, lag_num=2 -> width 5 (lags -2..+2), center idx2 NaN. + out = crp(recalls=np.array([[2, 1, 3]]), subjects=["a"], + listLength=3, lag_num=2) + assert out.shape == (1, 5) + assert np.isnan(out[0, 2]) + # 2->1: from sp2 poss lags {-1,+1}, actual -1. + # 1->3: from sp1 (seen {1,2}) poss lags {+2}, actual +2. + # lag -1 idx1: 1/1 = 1.0 ; lag +1 idx3: 0/1 = 0.0 ; lag +2 idx4: 1/1 = 1.0 + assert out[0, 1] == 1.0 + assert out[0, 3] == 0.0 + assert out[0, 4] == 1.0 + # lag -2 idx0 never possible -> NaN + assert np.isnan(out[0, 0]) + + +@pytest.mark.property +def test_crp_probabilities_in_unit_and_center_nan(): + _, _, recalls, exp = _matrices_no_repeats(seed=1) + out = crp(recalls=recalls, subjects=["s"] * len(recalls), + listLength=exp["list_length"], lag_num=5) + assert out.shape == (1, 11) + assert _in_unit_or_nan(out) + # center column (lag 0) is always NaN + assert np.isnan(out[0, 5]) + + +@pytest.mark.property +def test_crp_width_is_2lagnum_plus_1(): + _, _, recalls, exp = _matrices_no_repeats(seed=2) + for lag_num in (1, 3, 5, 7): + out = crp(recalls=recalls, subjects=["s"] * len(recalls), + listLength=exp["list_length"], lag_num=lag_num) + assert out.shape[1] == 2 * lag_num + 1 + + +@pytest.mark.property +def test_crp_lag_num_guards_raise(): + r = np.array([[1, 2, 3]]) + # lag_num < 1 + with pytest.raises(ValueError): + crp(recalls=r, subjects=["a"], listLength=4, lag_num=0) + # lag_num >= listLength + with pytest.raises(ValueError): + crp(recalls=r, subjects=["a"], listLength=4, lag_num=4) + # non-int lag_num + with pytest.raises(ValueError): + crp(recalls=r, subjects=["a"], listLength=4, lag_num=2.5) + # non-int skip_first_n + with pytest.raises(ValueError): + crp(recalls=r, subjects=["a"], listLength=4, lag_num=2, + skip_first_n=1.5) + + +@pytest.mark.edge_case +def test_crp_empty_recalls_all_nan(): + # No correct recalls -> no transitions -> every column NaN. + out = crp(recalls=np.zeros((1, 4), dtype=int), subjects=["a"], + listLength=4, lag_num=3) + assert out.shape == (1, 7) + assert np.all(np.isnan(out)) + + +@pytest.mark.edge_case +def test_crp_skip_first_n_removes_only_transition(): + # Single transition 2->3 but skip_first_n=1 skips it -> all NaN. + out = crp(recalls=np.array([[2, 3, 0, 0]]), subjects=["a"], + listLength=4, lag_num=3, skip_first_n=1) + assert np.all(np.isnan(out)) + + +# =========================================================================== +# min_crp (repeated-presentation lag-CRP) +# =========================================================================== +@pytest.mark.hand_coded +def test_min_crp_forward_matches_hand(): + # No repeats, forward recall: identical to crp by hand. + pres = np.array([[1, 2, 3, 4]]) + recalls = np.array([[1, 2, 3, 4]]) + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + out = min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=4, lag_num=3) + assert out.shape == (1, 7) + assert np.isnan(out[0, 3]) # center NaN + assert out[0, 4] == 1.0 # lag +1 + assert out[0, 5] == 0.0 # lag +2 + assert out[0, 6] == 0.0 # lag +3 + + +@pytest.mark.hand_coded +def test_min_crp_backward_then_forward(): + pres = np.array([[1, 2, 3]]) + recalls = np.array([[2, 1, 3]]) + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + out = min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=3, lag_num=2) + assert out.shape == (1, 5) + assert np.isnan(out[0, 2]) + assert out[0, 1] == 1.0 # lag -1 + assert out[0, 3] == 0.0 # lag +1 + assert out[0, 4] == 1.0 # lag +2 + + +@pytest.mark.hand_coded +def test_min_crp_single_transition(): + pres = np.array([[1, 2, 3, 4]]) + recalls = np.array([[2, 3, 0, 0]]) + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + out = min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=4, lag_num=3) + assert np.isnan(out[0, 3]) + assert out[0, 4] == 1.0 # lag +1 + assert out[0, 2] == 0.0 # lag -1 + assert out[0, 5] == 0.0 # lag +2 + + +@pytest.mark.property +def test_min_crp_probabilities_in_unit_and_center_nan(): + pres, _, recalls, exp = _matrices_no_repeats(seed=3) + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + out = min_crp(recalls=recalls, poss_recalls=poss, + subjects=["s"] * len(recalls), + listLength=exp["list_length"], lag_num=5) + assert _in_unit_or_nan(out) + assert np.isnan(out[0, 5]) + + +@pytest.mark.property +@pytest.mark.parametrize("seed", [1, 2, 3, 4, 5]) +def test_min_crp_agrees_with_crp_on_unique_items(seed): + # KEY CLAIM under scrutiny: with NO repeated presentations, the + # repeated-presentation min_crp must reduce to plain crp. Verified here + # element-wise (equal_nan) over the shared lag window for several seeds. + pres, _, recalls, exp = _matrices_no_repeats(seed=seed) + ll = exp["list_length"] + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + subj = ["s"] * len(recalls) + c = crp(recalls=recalls, subjects=subj, listLength=ll, lag_num=5) + m = min_crp(recalls=recalls, poss_recalls=poss, subjects=subj, + listLength=ll, lag_num=5) + assert np.allclose(c, m, equal_nan=True) + + +@pytest.mark.property +def test_min_crp_3d_repeated_path_in_unit(): + # Exercise the with_repeats (3D) branch; result still bounded. + exp = make_experiment(n_lists=4, list_length=8, p_intrusion=0.0, seed=6) + pres, rec = exp["pres_itemnos"], exp["rec_itemnos"] + rc3 = make_recalls_matrix(pres, rec, max_n_reps=2) + poss3 = make_poss_recalls_matrix(pres, max_n_reps=2) + assert rc3.ndim == 3 and poss3.ndim == 3 + out = min_crp(recalls=rc3, poss_recalls=poss3, + subjects=["s"] * len(rc3), listLength=8, lag_num=5) + assert _in_unit_or_nan(out) + assert np.isnan(out[0, 5]) + + +@pytest.mark.property +def test_min_crp_lag_num_guards_raise(): + pres = np.array([[1, 2, 3]]) + recalls = np.array([[1, 2, 3]]) + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + with pytest.raises(ValueError): + min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=3, lag_num=0) + with pytest.raises(ValueError): + min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=3, lag_num=3) + with pytest.raises(ValueError): + min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=3, lag_num=2, skip_first_n=0.5) + + +@pytest.mark.edge_case +def test_min_crp_empty_recalls_all_nan(): + pres = np.array([[1, 2, 3, 4]]) + recalls = np.zeros((1, 4), dtype=int) + poss = make_poss_recalls_matrix(pres_itemnos=pres, max_n_reps=1) + out = min_crp(recalls=recalls, poss_recalls=poss, subjects=["a"], + listLength=4, lag_num=3) + assert np.all(np.isnan(out)) + + +# =========================================================================== +# sem_crp +# =========================================================================== +@pytest.mark.hand_coded +def test_sem_crp_explicit_bins_hand(): + # listLength=3, forward recall [1,2,3]; sym sem matrix. + pres = np.array([[1, 2, 3]]) + rec = np.array([[1, 2, 3]]) + recalls = np.array([[1, 2, 3]]) + sem = np.array([[0., 1., 2.], [1., 0., 3.], [2., 3., 0.]]) + bins = [0.5, 1.5, 2.5] # 3 bins + with warnings.catch_warnings(): + warnings.simplefilter("ignore") # 0/0 in an empty bin_means cell + bm, c = sem_crp(recalls=recalls, recalls_itemnos=rec, + pres_itemnos=pres, subjects=["a"], sem_sims=sem, + bins=bins, listLength=3) + # Hand accounting (see analysis): actual=[1,0,1], poss=[1,1,1]. + assert c.shape == (1, 3) # crp row length == n_bins + assert bm.shape == c.shape # bin_means same shape as crp + np.testing.assert_array_equal(c[0], np.array([1.0, 0.0, 1.0])) + # bin_means: bin0 = 1/1 = 1, bin1 = 0/0 = nan, bin2 = 3/1 = 3. + assert bm[0, 0] == 1.0 + assert np.isnan(bm[0, 1]) + assert bm[0, 2] == 3.0 + + +@pytest.mark.hand_coded +def test_sem_crp_returns_two_tuple_and_four_tuple(): + pres = np.array([[1, 2, 3]]) + rec = np.array([[1, 2, 3]]) + recalls = np.array([[1, 2, 3]]) + sem = np.array([[0., 1., 2.], [1., 0., 3.], [2., 3., 0.]]) + bins = [0.5, 1.5, 2.5] + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + two = sem_crp(recalls=recalls, recalls_itemnos=rec, pres_itemnos=pres, + subjects=["a"], sem_sims=sem, bins=bins, listLength=3) + four = sem_crp(recalls=recalls, recalls_itemnos=rec, pres_itemnos=pres, + subjects=["a"], sem_sims=sem, bins=bins, listLength=3, + ret_counts=True) + assert len(two) == 2 + assert len(four) == 4 + _, _, actual, poss = four + np.testing.assert_array_equal(actual, np.array([1.0, 0.0, 1.0])) + np.testing.assert_array_equal(poss, np.array([1.0, 1.0, 1.0])) + + +@pytest.mark.hand_coded +def test_sem_crp_n_bins_controls_row_length(): + # With n_bins (no explicit bins) crp row length == n_bins. + pres, rec, recalls, exp = _matrices_no_repeats(seed=7) + sem = distance_matrix(exp["features"], exp["features"], p=2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + bm, c = sem_crp(recalls=recalls, recalls_itemnos=rec, + pres_itemnos=pres, subjects=["s"] * len(recalls), + sem_sims=sem, n_bins=7, + listLength=exp["list_length"]) + assert c.shape == (1, 7) + assert bm.shape == (1, 7) + + +@pytest.mark.property +def test_sem_crp_bounds_and_shapes(): + pres, rec, recalls, exp = _matrices_no_repeats(seed=8) + sem = distance_matrix(exp["features"], exp["features"], p=2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + bm, c = sem_crp(recalls=recalls, recalls_itemnos=rec, + pres_itemnos=pres, subjects=["s"] * len(recalls), + sem_sims=sem, n_bins=10, + listLength=exp["list_length"]) + # crp probabilities in [0,1] or NaN: the actual transition's bin is always + # among the possible-transition bins, so actual<=poss per bin (no >1). + assert _in_unit_or_nan(c) + assert bm.shape == c.shape + + +@pytest.mark.property +def test_sem_crp_poss_ge_actual_never_exceeds_one(): + # Directly assert the accounting invariant: for every populated bin, + # actual <= poss (so crp = actual/poss is never > 1). + pres, rec, recalls, exp = _matrices_no_repeats(seed=9) + sem = distance_matrix(exp["features"], exp["features"], p=2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + _, _, actual, poss = sem_crp( + recalls=recalls, recalls_itemnos=rec, pres_itemnos=pres, + subjects=["s"] * len(recalls), sem_sims=sem, n_bins=10, + listLength=exp["list_length"], ret_counts=True) + assert np.all(actual <= poss) + + +# =========================================================================== +# pd_crp +# =========================================================================== +@pytest.mark.property +def test_pd_crp_lag0_nan_and_bounds(): + exp = make_experiment(p_intrusion=0.0, seed=2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_crp(exp["events"], lag_num=5) + assert list(out.columns) == ["prob", "lag"] + # lag==0 row is NaN + assert np.isnan(out.loc[out["lag"] == 0, "prob"]).all() + # 2*lag_num+1 rows + assert len(out) == 11 + assert _in_unit_or_nan(out["prob"].values) + + +@pytest.mark.property +def test_pd_crp_matches_matrix_crp(): + # pd_crp should equal crp computed off the same matrices. + pres, rec, recalls, exp = _matrices_no_repeats(seed=2) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_crp(exp["events"], lag_num=5) + direct = crp(recalls=recalls, subjects=["s"] * len(recalls), + listLength=exp["list_length"], lag_num=5)[0] + np.testing.assert_allclose(out["prob"].values, direct, equal_nan=True) + + +@pytest.mark.edge_case +def test_pd_crp_no_valid_lists_returns_empty_df(): + # WORD-only df: no list has both presentations and recalls. + df = pd.DataFrame([ + dict(subject="s", session=0, list=0, type="WORD", itemno=1, + serialpos=1), + dict(subject="s", session=0, list=0, type="WORD", itemno=2, + serialpos=2), + ]) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_crp(df, lag_num=3) + assert isinstance(out, pd.DataFrame) + assert out.empty + + +# =========================================================================== +# pd_min_crp +# =========================================================================== +@pytest.mark.property +def test_pd_min_crp_default_max_n_reps_bounds(): + exp = make_experiment(p_intrusion=0.0, seed=4) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_min_crp(exp["events"], lag_num=5, max_n_reps=1) + assert list(out.columns) == ["prob", "lag"] + assert np.isnan(out.loc[out["lag"] == 0, "prob"]).all() + assert _in_unit_or_nan(out["prob"].values) + + +@pytest.mark.property +def test_pd_min_crp_agrees_with_pd_crp_no_repeats(): + # No repeated presentations -> pd_min_crp == pd_crp. + exp = make_experiment(p_intrusion=0.0, seed=5) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + a = pb.pd_crp(exp["events"], lag_num=5) + b = pb.pd_min_crp(exp["events"], lag_num=5, max_n_reps=1) + np.testing.assert_allclose(a["prob"].values, b["prob"].values, + equal_nan=True) + + +@pytest.mark.property +def test_pd_min_crp_max_n_reps_2_bounds(): + exp = make_experiment(n_lists=4, list_length=8, p_intrusion=0.0, seed=6) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_min_crp(exp["events"], lag_num=5, max_n_reps=2) + assert np.isnan(out.loc[out["lag"] == 0, "prob"]).all() + assert _in_unit_or_nan(out["prob"].values) + + +# =========================================================================== +# pd_sem_crp +# =========================================================================== +@pytest.mark.property +def test_pd_sem_crp_bounds_and_columns(): + exp = make_experiment(p_intrusion=0.0, seed=3) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp(exp["events"], sim_columns=exp["feat_cols"], + n_bins=10) + assert {"prob", "sem_bin_mean", "sem_bin"}.issubset(out.columns) + # at most n_bins rows (rows with no data are dropped by `prob == prob`) + assert len(out) <= 10 + assert _in_unit_or_nan(out["prob"].values) + # no dropped row is NaN (the query removes them) + assert not out["prob"].isna().any() + + +@pytest.mark.property +def test_pd_sem_crp_ret_counts_actual_le_poss(): + exp = make_experiment(p_intrusion=0.0, seed=3) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp(exp["events"], sim_columns=exp["feat_cols"], + n_bins=10, ret_counts=True) + assert {"actual", "poss"}.issubset(out.columns) + assert np.all(out["actual"].values <= out["poss"].values) + + +@pytest.mark.edge_case +def test_pd_sem_crp_no_valid_lists_returns_empty_df(): + df = pd.DataFrame([ + dict(subject="s", session=0, list=0, type="WORD", itemno=1, + serialpos=1, f0=0.1), + dict(subject="s", session=0, list=0, type="WORD_VALS", itemno=1, + serialpos=0, f0=0.1), + ]) + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp(df, sim_columns=["f0"], n_bins=3) + assert isinstance(out, pd.DataFrame) + assert out.empty + + +# =========================================================================== +# pd_sem_crp_list (one list; features off WORD rows; bins REQUIRED) +# =========================================================================== +def _one_list_df(exp, list_id=0): + df = exp["events"] + return df[(df["list"] == list_id) + & (df["type"].isin(["WORD", "REC_WORD"]))].copy() + + +@pytest.mark.property +def test_pd_sem_crp_list_bounds(): + exp = make_experiment(n_lists=4, list_length=8, p_intrusion=0.0, seed=5) + bins = list(np.linspace(0, 8, 6))[:-1] + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp_list(_one_list_df(exp), sim_columns=exp["feat_cols"], + bins=bins) + assert {"prob", "sem_bin_mean", "sem_bin"}.issubset(out.columns) + assert _in_unit_or_nan(out["prob"].values) + # rows with data are kept; at most len(bins) of them + assert len(out) <= len(bins) + + +@pytest.mark.property +def test_pd_sem_crp_list_ret_counts_actual_le_poss(): + exp = make_experiment(n_lists=4, list_length=8, p_intrusion=0.0, seed=5) + bins = list(np.linspace(0, 8, 6))[:-1] + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp_list(_one_list_df(exp), sim_columns=exp["feat_cols"], + bins=bins, ret_counts=True) + assert {"actual", "poss"}.issubset(out.columns) + assert np.all(out["actual"].values <= out["poss"].values) + + +# =========================================================================== +# pd_sem_crp_list_sub (groupby(list_index).apply); factory uses 'list' +# =========================================================================== +@pytest.mark.integration +def test_pd_sem_crp_list_sub_aggregates_bounds(): + exp = make_experiment(n_lists=4, list_length=8, p_intrusion=0.0, seed=5) + bins = list(np.linspace(0, 8, 6))[:-1] + sub_df = exp["events"][exp["events"]["type"].isin(["WORD", "REC_WORD"])] + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp_list_sub( + sub_df, sim_columns=exp["feat_cols"], bins=bins, + list_index=["subject", "session", "list"]) + assert {"sem_bin", "actual", "poss", "prob"}.issubset(out.columns) + # subject-level prob = summed actual / summed poss; bounded. + assert _in_unit_or_nan(out["prob"].values) + assert np.all(out["actual"].values <= out["poss"].values) + + +@pytest.mark.integration +def test_pd_sem_crp_list_sub_matches_manual_pool_sum(): + # The sub-level prob should equal sum(actual)/sum(poss) across that + # subject's lists, computed bin by bin. + exp = make_experiment(n_lists=4, list_length=8, p_intrusion=0.0, seed=5) + bins = list(np.linspace(0, 8, 6))[:-1] + sub_df = exp["events"][exp["events"]["type"].isin(["WORD", "REC_WORD"])] + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + out = pb.pd_sem_crp_list_sub( + sub_df, sim_columns=exp["feat_cols"], bins=bins, + list_index=["subject", "session", "list"]) + # prob == actual/poss exactly for each aggregated bin row + np.testing.assert_allclose( + out["prob"].values, + out["actual"].values / out["poss"].values, + equal_nan=True) diff --git a/tests/test_matrix.py b/tests/test_matrix.py new file mode 100644 index 0000000..5604b81 --- /dev/null +++ b/tests/test_matrix.py @@ -0,0 +1,451 @@ +"""Skeptical unit tests for the matrix-level helpers in ``pybeh_pd``. + +Functions under test (all ``pb.``): + get_itemno_matrices, get_all_matrices, make_recalls_matrix, + make_poss_recalls_matrix, get_min_trans, get_sim_mat, + make_clean_recalls_mask2d (from pybeh_copy, re-exported on pb). + +Conventions tested: + pres/rec itemnos are positive ints; rec rows 0-padded; extra-list + intrusions become -1 in the recalls matrix; correct recalls become the + 1-based serial position of the item in its presentation row. + +Markers: hand_coded, property, edge_case, pins_bug (see pytest.ini). +""" +from __future__ import annotations + +import numpy as np +import pandas as pd +import pytest + +import pybeh_pd as pb +from factories import make_experiment + + +# --------------------------------------------------------------------------- +# make_recalls_matrix +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_make_recalls_matrix_basic_serialpos(): + # pres item k is at serial position k+1; recalled items map to those sps, + # padding 0 stays 0. + pres = np.array([[1, 2, 3, 4]]) + rec = np.array([[3, 1, 4, 0]]) + out = pb.make_recalls_matrix(pres, rec) + assert out.shape == (1, 4) + np.testing.assert_array_equal(out, np.array([[3, 1, 4, 0]])) + + +@pytest.mark.hand_coded +def test_make_recalls_matrix_extra_list_intrusion_maps_to_minus_one(): + # itemno 5 is not in the presentation row -> -1. + pres = np.array([[1, 2, 3, 4]]) + rec = np.array([[5, 2, 0, 0]]) + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.array([[-1, 2, 0, 0]])) + + +@pytest.mark.hand_coded +def test_make_recalls_matrix_zero_in_middle_stays_zero(): + # A 0 anywhere in the recall row is "no recall" -> stays 0, surrounding + # correct recalls still map to serial positions. + pres = np.array([[10, 20, 30]]) + rec = np.array([[20, 0, 30]]) + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.array([[2, 0, 3]])) + + +@pytest.mark.property +def test_make_recalls_matrix_correct_entries_are_valid_serialpos(): + exp = make_experiment(seed=11) + pres = exp["pres_itemnos"] + rec = exp["rec_itemnos"] + L = exp["list_length"] + out = pb.make_recalls_matrix(pres, rec) + assert out.shape == rec.shape + for t in range(out.shape[0]): + for r in range(out.shape[1]): + v = out[t, r] + if v > 0: + # valid serial position in 1..L + assert 1 <= v <= L + # and the item at that position equals the recalled itemno + assert pres[t, v - 1] == rec[t, r] + elif v == 0: + # padding only where the recall itemno was 0 padding + assert rec[t, r] == 0 + else: + # intrusion: -1, and the recalled itemno is genuinely absent + assert v == -1 + assert rec[t, r] not in set(pres[t].tolist()) + + +@pytest.mark.property +def test_make_recalls_matrix_max_n_reps_2_returns_3d(): + # Item 5 presented at positions 1 and 3 (doubled). With max_n_reps=2 the + # output is 3D (trials, recalls, 2) and a correct recall of 5 records both + # serial positions [1, 3]. + pres = np.array([[5, 6, 5, 7]]) + rec = np.array([[5, 7, 0]]) + out = pb.make_recalls_matrix(pres, rec, max_n_reps=2) + assert out.shape == (1, 3, 2) + np.testing.assert_array_equal(out[0, 0], np.array([1, 3])) # both sps of "5" + np.testing.assert_array_equal(out[0, 1], np.array([4, 0])) # "7" single sp + np.testing.assert_array_equal(out[0, 2], np.array([0, 0])) # padding + + +@pytest.mark.edge_case +def test_make_recalls_matrix_doubled_item_raises_with_default_max_n_reps(): + # Item 1 presented twice; with max_n_reps=1 recalling it finds 2 serial + # positions -> Exception. + pres = np.array([[1, 1, 2]]) + rec = np.array([[1, 0, 0]]) + with pytest.raises(Exception, match="more than max_n_reps"): + pb.make_recalls_matrix(pres, rec, max_n_reps=1) + + +@pytest.mark.edge_case +def test_make_recalls_matrix_empty_recall_row_all_zero(): + pres = np.array([[1, 2, 3]]) + rec = np.array([[0, 0, 0]]) + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.zeros((1, 3), dtype=int)) + + +@pytest.mark.edge_case +def test_make_recalls_matrix_all_intrusions(): + pres = np.array([[1, 2, 3]]) + rec = np.array([[7, 8, 9]]) # none presented + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.array([[-1, -1, -1]])) + + +@pytest.mark.edge_case +def test_make_recalls_matrix_single_item_list(): + pres = np.array([[42]]) + rec = np.array([[42, 0]]) + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.array([[1, 0]])) + + +@pytest.mark.edge_case +def test_make_recalls_matrix_rec_longer_than_pres(): + # rec row may have more columns than the list length; trailing zeros pad. + pres = np.array([[1, 2]]) + rec = np.array([[2, 1, 0, 0, 0]]) + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.array([[2, 1, 0, 0, 0]])) + + +@pytest.mark.pins_bug +def test_make_recalls_matrix_nan_padding_misclassified_as_intrusion(): + # BUG (B-NEW, pybeh_pd.py:74): the docstring says recall rows "may be padded + # with zeros or NaNs", but the zero/NaN guard is written + # (rec_itemnos[t,r]) == 0 | (np.isnan(rec_itemnos[t,r])) + # which, due to Python operator precedence (| binds tighter than ==), + # evaluates as rec == (0 | isnan) instead of (rec == 0) | isnan. + # For a NaN entry: 0 | True == 1, and nan == 1 is False, so the NaN falls + # through to the else branch and is recorded as an INTRUSION (-1) rather + # than padding (0). + # + # CORRECT behavior would be 0 (padding). We pin the current buggy -1. + pres = np.array([[1.0, 2.0, 3.0]]) + rec = np.array([[2.0, np.nan, 3.0]]) + out = pb.make_recalls_matrix(pres, rec) + np.testing.assert_array_equal(out, np.array([[2, -1, 3]])) # bug: nan -> -1 + + +# --------------------------------------------------------------------------- +# make_poss_recalls_matrix +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_make_poss_recalls_unique_items_identity(): + # On a unique-item list every item maps to its own serial position. + pres = np.array([[10, 20, 30, 40]]) + out = pb.make_poss_recalls_matrix(pres) + np.testing.assert_array_equal(out, np.array([[1, 2, 3, 4]])) + + +@pytest.mark.hand_coded +def test_make_poss_recalls_zero_padding_stays_zero(): + pres = np.array([[5, 6, 0]]) + out = pb.make_poss_recalls_matrix(pres) + np.testing.assert_array_equal(out, np.array([[1, 2, 0]])) + + +@pytest.mark.hand_coded +def test_make_poss_recalls_repeated_item_max_n_reps_2(): + # Item 5 at positions 1 and 3 -> both rows for that item record [1, 3]. + pres = np.array([[5, 6, 5, 7]]) + out = pb.make_poss_recalls_matrix(pres, max_n_reps=2) + assert out.shape == (1, 4, 2) + np.testing.assert_array_equal(out[0, 0], np.array([1, 3])) + np.testing.assert_array_equal(out[0, 1], np.array([2, 0])) + np.testing.assert_array_equal(out[0, 2], np.array([1, 3])) + np.testing.assert_array_equal(out[0, 3], np.array([4, 0])) + + +@pytest.mark.property +def test_make_poss_recalls_unique_lists_is_arange(): + exp = make_experiment(seed=7) + pres = exp["pres_itemnos"] + L = exp["list_length"] + out = pb.make_poss_recalls_matrix(pres) + assert out.shape == pres.shape + expected = np.tile(np.arange(1, L + 1), (pres.shape[0], 1)) + np.testing.assert_array_equal(out, expected) + + +@pytest.mark.edge_case +def test_make_poss_recalls_doubled_item_raises_max_n_reps_1(): + pres = np.array([[3, 3, 4]]) + with pytest.raises(Exception, match="more than max_n_reps"): + pb.make_poss_recalls_matrix(pres, max_n_reps=1) + + +# --------------------------------------------------------------------------- +# get_min_trans +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_get_min_trans_positive_wins_tie(): + # candidates serialpos [1, 3], current recall rec=[2]: + # diffs sp - r = {1-2=-1, 3-2=+1}. abs equal -> Howard&Kahana rule: + # sort descending [+1, -1] then argmin(|.|) picks the first, +1. + assert pb.get_min_trans([1, 3], [2]) == 1 + + +@pytest.mark.hand_coded +def test_get_min_trans_zero_when_same_position(): + # rec position equals a candidate -> lag 0 (smallest abs). + assert pb.get_min_trans([1, 2, 3], [2]) == 0 + + +@pytest.mark.hand_coded +def test_get_min_trans_picks_smallest_abs_lag(): + # candidates [1, 10], rec=[3]: diffs {-2, +7} -> smallest abs is -2. + assert pb.get_min_trans([1, 10], [3]) == -2 + + +@pytest.mark.property +def test_get_min_trans_result_is_a_realizable_lag(): + rng = np.random.default_rng(0) + for _ in range(50): + sp = sorted(rng.choice(np.arange(1, 12), size=rng.integers(1, 5), replace=False).tolist()) + rec = [int(rng.integers(1, 12))] + res = pb.get_min_trans(sp, rec) + all_lags = [s - r for s in sp for r in rec] + # result is one of the candidate lags and has minimal abs value + assert res in all_lags + assert abs(res) == min(abs(x) for x in all_lags) + # tie-break: among minimal-abs lags, the most positive one is chosen + min_abs = min(abs(x) for x in all_lags) + tied = [x for x in all_lags if abs(x) == min_abs] + assert res == max(tied) + + +# --------------------------------------------------------------------------- +# make_clean_recalls_mask2d (from pybeh_copy) +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_clean_mask_first_correct_only(): + # 1 only for the first occurrence of each positive value; repeats/0/neg -> 0. + data = np.array([[3, 1, 1, 0, -1]]) + out = np.array(pb.make_clean_recalls_mask2d(data)) + np.testing.assert_array_equal(out, np.array([[1, 1, 0, 0, 0]])) + + +@pytest.mark.hand_coded +def test_clean_mask_repeat_then_new(): + data = np.array([[2, 2, -1, 3, 0]]) + out = np.array(pb.make_clean_recalls_mask2d(data)) + np.testing.assert_array_equal(out, np.array([[1, 0, 0, 1, 0]])) + + +@pytest.mark.hand_coded +def test_clean_mask_all_zero_and_all_negative(): + data = np.array([[0, 0, 0], [-1, -2, -1]]) + out = np.array(pb.make_clean_recalls_mask2d(data)) + np.testing.assert_array_equal(out, np.zeros((2, 3), dtype=int)) + + +@pytest.mark.property +def test_clean_mask_is_binary_and_marks_first_occurrence(): + exp = make_experiment(seed=5) + recalls = pb.make_recalls_matrix(exp["pres_itemnos"], exp["rec_itemnos"]) + out = np.array(pb.make_clean_recalls_mask2d(recalls)) + assert out.shape == recalls.shape + # strictly 0/1 + assert set(np.unique(out).tolist()).issubset({0, 1}) + # mask == 1 exactly at first occurrence of each positive serial position + for row_in, row_out in zip(recalls, out): + seen: set[int] = set() + for v_in, v_out in zip(row_in, row_out): + expected = 1 if (v_in > 0 and v_in not in seen) else 0 + assert v_out == expected + if v_in > 0: + seen.add(int(v_in)) + + +# --------------------------------------------------------------------------- +# get_sim_mat +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_get_sim_mat_euclidean_hand_values(): + # Two WORD_VALS items at (0,0) and (3,4) -> distance 5, symmetric, 0 diag. + df = pd.DataFrame({ + "type": ["WORD_VALS", "WORD_VALS"], + "itemno": [1, 2], + "f0": [0.0, 3.0], + "f1": [0.0, 4.0], + }) + sm = pb.get_sim_mat(df, ["f0", "f1"]) + assert sm.shape == (2, 2) + np.testing.assert_allclose(sm, np.array([[0.0, 5.0], [5.0, 0.0]])) + + +@pytest.mark.hand_coded +def test_get_sim_mat_p1_manhattan(): + df = pd.DataFrame({ + "type": ["WORD_VALS", "WORD_VALS"], + "itemno": [1, 2], + "f0": [0.0, 3.0], + "f1": [0.0, 4.0], + }) + sm = pb.get_sim_mat(df, ["f0", "f1"], p=1) + np.testing.assert_allclose(sm, np.array([[0.0, 7.0], [7.0, 0.0]])) + + +@pytest.mark.hand_coded +def test_get_sim_mat_sorts_by_itemno(): + # Rows given out of itemno order; output should be sorted so item 1 is row 0. + df = pd.DataFrame({ + "type": ["WORD_VALS", "WORD_VALS"], + "itemno": [2, 1], + "f0": [10.0, 0.0], + "f1": [0.0, 0.0], + }) + sm = pb.get_sim_mat(df, ["f0", "f1"]) + # both off-diagonals equal the distance 10, diagonal 0 + np.testing.assert_allclose(sm, np.array([[0.0, 10.0], [10.0, 0.0]])) + + +@pytest.mark.property +def test_get_sim_mat_symmetric_zero_diag_shape(): + exp = make_experiment(seed=2) + sm = pb.get_sim_mat(exp["events"], exp["feat_cols"]) + pool = exp["n_lists"] * exp["list_length"] + assert sm.shape == (pool, pool) + # Minkowski self-distance is 0 on the diagonal + np.testing.assert_allclose(np.diag(sm), np.zeros(pool), atol=1e-12) + # symmetric + np.testing.assert_allclose(sm, sm.T, atol=1e-12) + # non-negative + assert (sm >= 0).all() + + +# --------------------------------------------------------------------------- +# get_itemno_matrices +# --------------------------------------------------------------------------- + +@pytest.mark.hand_coded +def test_get_itemno_matrices_pivots_to_serialpos_order(): + df = pd.DataFrame({ + "subject": ["s0"] * 4, + "session": [0] * 4, + "list": [0, 0, 1, 1], + "itemno": [11, 12, 21, 22], + }) + out = pb.get_itemno_matrices(df) + assert out.shape == (2, 2) + np.testing.assert_array_equal(out, np.array([[11, 12], [21, 22]])) + + +@pytest.mark.property +def test_get_itemno_matrices_padding_for_ragged_lists(): + # List 0 has 3 items, list 1 has 2 -> ragged; shorter row padded with 0. + df = pd.DataFrame({ + "subject": ["s0"] * 5, + "session": [0] * 5, + "list": [0, 0, 0, 1, 1], + "itemno": [1, 2, 3, 4, 5], + }) + out = pb.get_itemno_matrices(df) + assert out.shape == (2, 3) + np.testing.assert_array_equal(out, np.array([[1, 2, 3], [4, 5, 0]])) + + +@pytest.mark.property +def test_get_itemno_matrices_matches_factory_pres(): + exp = make_experiment(seed=9) + word_df = exp["events"].query("type == 'WORD'").copy() + out = pb.get_itemno_matrices(word_df) + np.testing.assert_array_equal(out, exp["pres_itemnos"]) + + +# --------------------------------------------------------------------------- +# get_all_matrices +# --------------------------------------------------------------------------- + +@pytest.mark.property +def test_get_all_matrices_shapes_and_consistency(): + exp = make_experiment(seed=4) + pres, rec, recalls = pb.get_all_matrices(exp["events"].copy()) + L = exp["list_length"] + assert pres.shape[1] == L + assert recalls.shape == rec.shape + assert pres.shape[0] == exp["n_lists"] + # recalls derived consistently with pres/rec + for t in range(recalls.shape[0]): + for r in range(recalls.shape[1]): + v = recalls[t, r] + if v > 0: + assert pres[t, v - 1] == rec[t, r] + elif v == 0: + assert rec[t, r] == 0 + + +@pytest.mark.property +def test_get_all_matrices_matches_factory_pres_matrix(): + exp = make_experiment(seed=8) + pres, rec, recalls = pb.get_all_matrices(exp["events"].copy()) + np.testing.assert_array_equal(pres, exp["pres_itemnos"]) + + +@pytest.mark.edge_case +def test_get_all_matrices_drops_lists_missing_a_type(): + # A list with WORD rows but no REC_WORD rows (and vice versa) is excluded, + # because get_all_matrices keeps only lists where both types are present. + rows = [] + # list 0: complete (pres + rec) + for pos, ino in enumerate([1, 2, 3]): + rows.append(dict(subject="s0", session=0, list=0, type="WORD", itemno=ino)) + for ino in [2, 1]: + rows.append(dict(subject="s0", session=0, list=0, type="REC_WORD", itemno=ino)) + # list 1: presentations only (no recalls) -> should be dropped + for ino in [4, 5, 6]: + rows.append(dict(subject="s0", session=0, list=1, type="WORD", itemno=ino)) + df = pd.DataFrame(rows) + pres, rec, recalls = pb.get_all_matrices(df) + # only one list survives + assert pres.shape[0] == 1 + assert rec.shape[0] == 1 + np.testing.assert_array_equal(pres, np.array([[1, 2, 3]])) + np.testing.assert_array_equal(recalls[0], np.array([2, 1])) + + +@pytest.mark.edge_case +def test_get_all_matrices_intrusion_in_events_maps_to_minus_one(): + rows = [] + for ino in [1, 2, 3]: + rows.append(dict(subject="s0", session=0, list=0, type="WORD", itemno=ino)) + # recall includes itemno 99 which was never presented on this list + for ino in [2, 99, 1]: + rows.append(dict(subject="s0", session=0, list=0, type="REC_WORD", itemno=ino)) + df = pd.DataFrame(rows) + pres, rec, recalls = pb.get_all_matrices(df) + np.testing.assert_array_equal(recalls[0], np.array([2, -1, 1])) From 0c7bc7711abe151c49a917b3ccf1066f88a9d0ef Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 01:31:31 +0000 Subject: [PATCH 07/15] test: add ltpFR2 real-data integration tests via cmlreaders Loads 5 sessions of real ltpFR2 scalp-EEG free-recall data from rhino and runs the pybeh_pd pipeline, asserting the temporal contiguity effect (lag+1 CRP is the max, forward asymmetry, lag 0 NaN) and above-chance temporal clustering. Verifies the direct per-subject call equals the canonical groupby('subject').apply(pd_crp) convention from the lab notebooks, and that the synthetic fixture mirrors the real event schema. Gated behind needs_data (cmlreaders + rhino mount); skipped otherwise (6-7 skipped off-rhino). --- pytest.ini | 1 + tests/real_data.py | 70 ++++++++++++++++++++++ tests/test_real_data.py | 126 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 tests/real_data.py create mode 100644 tests/test_real_data.py diff --git a/pytest.ini b/pytest.ini index 304f129..43b675b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -8,3 +8,4 @@ markers = regression: golden-master behavior lock integration: end-to-end pipeline on synthetic or real data pins_bug: pins CURRENT (known-buggy) behavior; see bug_report.md + needs_data: requires rhino mount + cmlreaders (real ltpFR2 data); skipped otherwise diff --git a/tests/real_data.py b/tests/real_data.py new file mode 100644 index 0000000..9b7d3b2 --- /dev/null +++ b/tests/real_data.py @@ -0,0 +1,70 @@ +"""Real-data loader for ltpFR2 integration tests. + +Loads behavioral events for a handful of ltpFR2 (scalp-EEG free recall) sessions +from rhino via ``cmlreaders`` and reshapes them into the long-format schema the +``pybeh_pd`` ``pd_*`` functions expect: + + columns: subject, session, list, type ('WORD'|'REC_WORD'), item_num, serialpos + +Notes on the ltpFR2 event schema (see `LtpFR2 - Data Set Description.pdf`): +- ``item_num`` is the 1-based wordpool item id (the ``itemno`` pybeh_pd needs). +- the real list number lives in ``trial``; the ``list`` field is a junk -999, so + we drop ``list`` and rename ``trial`` -> ``list`` (matching the lab's own + loader in subjective_item_memorability/load_behavioral_data.py). +- encoding events are ``WORD``; retrieval events are ``REC_WORD``. + +These are gated behind :func:`ltpfr2_available` so the suite skips cleanly off +rhino or without cmlreaders installed. Data are loaded live (never committed). +""" +from __future__ import annotations + +import functools +import os + +RHINO_ROOT = "/" +LTPFR2_PROTOCOL_DIR = "/protocols/ltp" + + +def ltpfr2_available() -> bool: + """True iff cmlreaders is importable and the ltp protocol tree is mounted.""" + if not os.path.isdir(LTPFR2_PROTOCOL_DIR): + return False + try: + import cmlreaders # noqa: F401 + except Exception: + return False + return True + + +@functools.lru_cache(maxsize=8) +def load_ltpfr2_long(subject: str = "LTP093", n_sessions: int = 5): + """Load the first ``n_sessions`` of one ltpFR2 subject as a long DataFrame. + + Cached so the (slow) rhino read happens once per (subject, n_sessions). + Returns a DataFrame with columns + [subject, session, list, type, item_num, serialpos], containing only WORD + and REC_WORD events. Session 23 (a different wordpool) is skipped. + """ + import cmlreaders as cml + import pandas as pd + + idx = cml.get_data_index("ltp", rootdir=RHINO_ROOT).query( + "experiment == 'ltpFR2'") + rows = ( + idx.query("subject == @subject and session != 23") + .sort_values("session") + .head(n_sessions) + ) + keep = ["subject", "session", "list", "type", "item_num", "serialpos"] + frames = [] + for r in rows.itertuples(): + ev = cml.CMLReader( + subject=r.subject, session=int(r.session), + experiment="ltpFR2", rootdir=RHINO_ROOT, + ).load("events") + if "list" in ev.columns: + ev = ev.drop(columns="list") + ev = ev.rename(columns={"trial": "list"}) + ev = ev.query("type in ['WORD', 'REC_WORD']") + frames.append(ev[keep]) + return pd.concat(frames, ignore_index=True) diff --git a/tests/test_real_data.py b/tests/test_real_data.py new file mode 100644 index 0000000..4a8a7a5 --- /dev/null +++ b/tests/test_real_data.py @@ -0,0 +1,126 @@ +"""Real-data integration tests on 5 ltpFR2 sessions (loaded via cmlreaders). + +These run the actual ``pybeh_pd`` pipeline on real scalp-EEG free-recall data and +assert the well-established empirical signatures of free recall — the *temporal +contiguity effect* (Kahana 1996) and above-chance *temporal clustering* (Polyn, +Norman & Kahana 2009). They also confirm the synthetic fixture factory mirrors the +real event schema, which is what licenses the synthetic-data unit tests elsewhere. + +Skipped automatically off rhino / without cmlreaders. Data are loaded live and +never committed. +""" +from __future__ import annotations + +import numpy as np +import pytest + +import pybeh_pd as pb +from real_data import ltpfr2_available, load_ltpfr2_long +from factories import make_experiment + +pytestmark = [ + pytest.mark.needs_data, + pytest.mark.integration, + pytest.mark.skipif(not ltpfr2_available(), + reason="ltpFR2 data / cmlreaders not available"), +] + +ITEMNO = "item_num" +LIST_LENGTH = 24 # ltpFR2 lists are 24 items + + +@pytest.fixture(scope="module") +def ltpfr2(): + return load_ltpfr2_long(subject="LTP093", n_sessions=5) + + +# --- sanity: we actually loaded 5 sessions of valid free-recall data --------- + +def test_loaded_five_sessions(ltpfr2): + assert ltpfr2["session"].nunique() == 5 + assert set(ltpfr2["type"].unique()) == {"WORD", "REC_WORD"} + # 24 lists/session x 24 items = 576 study events per session + study = ltpfr2.query("type == 'WORD'") + per_sess = study.groupby("session")["list"].nunique() + assert (per_sess == 24).all() + assert (study.groupby(["session", "list"]).size() == LIST_LENGTH).all() + + +# --- the synthetic factory mirrors the real schema (validates fixtures) ------ + +def test_synthetic_fixture_mirrors_real_schema(ltpfr2): + syn = make_experiment(seed=0)["events"] + for col in ["subject", "session", "list", "type"]: + assert col in ltpfr2.columns and col in syn.columns + # both encode presentations as WORD and recalls as REC_WORD + assert {"WORD", "REC_WORD"}.issubset(set(syn["type"].unique())) + assert {"WORD", "REC_WORD"} == set(ltpfr2["type"].unique()) + # both carry a 1-based integer item id and a serialpos + assert (ltpfr2.query("type=='WORD'")[ITEMNO] > 0).all() + assert (syn.query("type=='WORD'")["itemno"] > 0).all() + + +# --- lag-CRP: temporal contiguity effect ------------------------------------- + +def test_pd_crp_contiguity_and_asymmetry(ltpfr2): + crp = pb.pd_crp(ltpfr2, lag_num=5, itemno_column=ITEMNO).set_index("lag") + prob = crp["prob"] + # lag 0 is undefined + assert np.isnan(prob.loc[0]) + # all probabilities are valid + valid = prob.drop(index=0) + assert ((valid >= 0) & (valid <= 1)).all() + # contiguity: adjacent transitions dominate distant ones + assert prob.loc[1] > prob.loc[5] + assert prob.loc[-1] > prob.loc[-5] + # +1 is the single most likely transition + assert prob.loc[1] == valid.max() + # forward asymmetry: forward adjacency beats backward adjacency + assert prob.loc[1] > prob.loc[-1] + + +# --- temporal clustering factor: above chance -------------------------------- + +def test_pd_crp_matches_groupby_apply_convention(ltpfr2): + """The canonical usage (FR1_analyses.ipynb cell 10) is + ``events.groupby('subject').apply(pb.pd_crp, itemno_column='item_num')``. + For a single subject that must equal the direct per-subject call, confirming + we drive pybeh_pd the way the lab's notebooks do.""" + import warnings + direct = pb.pd_crp(ltpfr2, itemno_column=ITEMNO).sort_values("lag")["prob"].values + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + grouped = ( + ltpfr2.groupby("subject") + .apply(pb.pd_crp, itemno_column=ITEMNO) + .reset_index() + ) + via = grouped.sort_values("lag")["prob"].values + assert np.allclose(direct, via, equal_nan=True) + + +def test_pd_temp_fact_above_chance(ltpfr2): + tf = pb.pd_temp_fact(ltpfr2, itemno_column=ITEMNO) + # chance is 0.5; ltpFR2 shows strong clustering + assert 0.5 < tf <= 1.0 + assert tf > 0.6 + + +def test_temp_fact_per_session_above_chance(ltpfr2): + for sess, g in ltpfr2.groupby("session"): + tf = pb.pd_temp_fact(g, itemno_column=ITEMNO) + assert 0.5 < tf <= 1.0, f"session {sess}: temp_fact={tf}" + + +# --- matrix builders produce valid serial positions on real data ------------ + +def test_get_all_matrices_valid_serialpos(ltpfr2): + pres, rec, recalls = pb.get_all_matrices(ltpfr2, itemno_column=ITEMNO) + assert pres.shape[1] == LIST_LENGTH + assert recalls.shape == rec.shape + # recalls entries are padding (0), intrusion (-1), or a serial position 1..24 + uniq = np.unique(recalls) + assert uniq.min() >= -1 + assert recalls.max() <= LIST_LENGTH + correct = recalls[recalls > 0] + assert ((correct >= 1) & (correct <= LIST_LENGTH)).all() From bb51747bc5580c9fc3b456d96a1198843cdf0590 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 01:41:34 +0000 Subject: [PATCH 08/15] build: add pixi rhino env (cmlreaders) for real-data tests Adds a 'rhino' pixi environment installing cmlreaders from git (no-build-isolation, since its setup.py imports pandas) so the ltpFR2 integration tests run via pixi, not just the lab conda env. Reworked the per-subject equivalence test to express the canonical groupby-apply decomposition by explicit slicing: the literal groupby('subject').apply(pd_crp) idiom breaks on pandas 3 (grouping column dropped; logged as a pandas-3 compat follow-up). Real-data suite now passes on pandas 2.3 and 3.0. --- pixi.lock | 1214 +++++++++++++++++++++++++++++++++++++++ pixi.toml | 16 + tests/test_real_data.py | 31 +- 3 files changed, 1247 insertions(+), 14 deletions(-) diff --git a/pixi.lock b/pixi.lock index 88aef25..eca3d85 100644 --- a/pixi.lock +++ b/pixi.lock @@ -544,6 +544,222 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + rhino: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.10.3-hea842a7_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.14-h78948cc_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.14.0-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.2-haa0cbde_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.11.0-h6488f85_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.26.3-h5b668fc_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.12.5-hb916526_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.4-haa0cbde_6.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.10-haa0cbde_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311hfef529e_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-2.1.0-nompi_h735b18d_107.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.7.3-hc5a330e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda + - pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd + osx-64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-auth-0.10.3-h2dfa1e0_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-cal-0.9.14-hcb77be1_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-common-0.14.0-ha1e9b39_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-compression-0.3.2-ha04291d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-http-0.11.0-he315c99_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-io-0.26.3-hd35ae92_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-s3-0.12.5-h8cc6e82_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-sdkutils-0.2.4-ha04291d_6.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-checksums-0.2.10-ha04291d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.16.0-nompi_py311ha7e68cf_102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-2.1.0-nompi_h3bd5531_107.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.5-he7c3a48_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.20.0-h8f0b9e4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.15-ha9537fe_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + - pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd + osx-arm64: + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.10.3-hceed5df_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.14-h81c6212_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-common-0.14.0-h84a0fba_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-compression-0.3.2-h61d3404_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-http-0.11.0-h0a63974_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-io-0.26.3-h58c0f83_4.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-s3-0.12.5-h43def2a_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-sdkutils-0.2.4-h61d3404_6.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-checksums-0.2.10-h61d3404_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/h5py-3.16.0-nompi_py311hf10ccac_102.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-2.1.0-nompi_h9bfbf6c_107.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libaec-1.1.5-h8664d51_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.15-h8561d8f_0_cpython.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + - pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda build_number: 20 @@ -556,8 +772,132 @@ packages: - openmp_impl <0.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 28948 timestamp: 1770939786096 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.10.3-hea842a7_2.conda + sha256: 5b9c20a38fe084b4ffd1f2c64b3797ec6ef9a99e83cc0c1f84e016c9801e3a5c + md5: c463d2dbfb12a208c943165d2a568db4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 134385 + timestamp: 1780598328124 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.14-h78948cc_2.conda + sha256: 06a0e2af439b21c94adff8fac5dd66dbda5f182fc80ac635c4903959ea306cbb + md5: fe81235aae00f32df8584267b4f2daf8 + depends: + - __glibc >=2.17,<3.0.a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - libgcc >=14 + - openssl >=3.5.6,<4.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 57011 + timestamp: 1780566647051 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.14.0-hb03c661_0.conda + sha256: 6d2b33965bf6daeffd3ad336f41410053ff06ed6f2b2ce62c1ec27c0a39b4e7e + md5: f1c005b2e3b618706112ddd7f3af4521 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 242497 + timestamp: 1780160843944 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.2-haa0cbde_2.conda + sha256: 0e4952f9be8de7f281ca7d734a3a8f05ad0db856c6ef1e0897798c4afbcd9a54 + md5: 595911421e25551e36fde7027bf33f38 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 22007 + timestamp: 1780566239465 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.11.0-h6488f85_2.conda + sha256: d2b844db1a4dfbc20b5129b7df4a656c1459c5fb16745101bbd802813ba8d411 + md5: da0be1e8cb4a43c876f26d9d812dea06 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - aws-c-compression >=0.3.2,<0.3.3.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 230293 + timestamp: 1780586764553 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.26.3-h5b668fc_4.conda + sha256: c27b972325342f062da00b7aa2d5abf6f3ce55668a05703a175be958745cc226 + md5: 555400dce62f2d989ff77761c010d166 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - s2n >=1.7.3,<1.7.4.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 181627 + timestamp: 1780575920109 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.12.5-hb916526_1.conda + sha256: 8f193173f1dccb25ff86a95543db27f0c762cccfe93157b02cf20bd5b4c11a92 + md5: 70bc8e5e8cefd19407423733e7ebf540 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - aws-checksums >=0.2.10,<0.2.11.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + - openssl >=3.5.6,<4.0a0 + - aws-c-auth >=0.10.3,<0.10.4.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 153453 + timestamp: 1780609553521 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.4-haa0cbde_6.conda + sha256: 123c4325b16f1f6db95846d51e5e4201399ee29c0325f8b5a8db2e7d732b9151 + md5: 4b66ac29a7e917a629b790c3d239d110 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 59085 + timestamp: 1780568538653 +- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.10-haa0cbde_2.conda + sha256: ad49333d96a5f9bcce02752a6515cbb077d7513e358a8fb1a832f4e772d54bac + md5: 5c05a63452bf73c50aa272a6f961c4fc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 101627 + timestamp: 1780568539000 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 md5: d2ffd7602c02f2b316fd921d39876885 @@ -566,8 +906,20 @@ packages: - libgcc >=14 license: bzip2-1.0.6 license_family: BSD + purls: [] size: 260182 timestamp: 1771350215188 +- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda + sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e + md5: 920bb03579f15389b9e512095ad995b7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 207882 + timestamp: 1765214722852 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda sha256: ebefe7c8a41d14e4a50c5b862cf0226b3ac745495415bb6fb0db364b945cfe3a md5: f875c239f662e1b31fbf32282f1da087 @@ -579,6 +931,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 399156 timestamp: 1779838054673 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py312h8a5da7c_0.conda @@ -607,6 +961,73 @@ packages: license_family: APACHE size: 396489 timestamp: 1779837909103 +- conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311hfef529e_102.conda + sha256: 9495b6fe2a7b1cf0fded3c53252e964d968fa1fc87cf1ce76c4d9c5e8ab22385 + md5: 5737f2130791c91aee8374ee0d4465de + depends: + - __glibc >=2.17,<3.0.a0 + - cached-property + - hdf5 >=2.1.0,<3.0a0 + - libgcc >=14 + - numpy >=1.23,<3 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/h5py?source=hash-mapping + size: 1359434 + timestamp: 1775581283533 +- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-2.1.0-nompi_h735b18d_107.conda + sha256: ff8336394dcfaccf49e56d1dd66091cf767df0d3d33f3fa440c980e0445b34cc + md5: b1b444bca8da3ff6cc4afad1fa7f7d61 + depends: + - __glibc >=2.17,<3.0.a0 + - aws-c-auth >=0.10.3,<0.10.4.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-s3 >=0.12.5,<0.12.6.0a0 + - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 + - libaec >=1.1.5,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + - libstdcxx >=14 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4610890 + timestamp: 1780923415022 +- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 + md5: b38117a3c920364aff79f870c984b4a3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + purls: [] + size: 134088 + timestamp: 1754905959823 +- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda + sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 + md5: fb53fb07ce46a575c5d004bbc96032c2 + depends: + - __glibc >=2.17,<3.0.a0 + - keyutils >=1.6.3,<2.0a0 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - libgcc >=14 + - libstdcxx >=14 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1386730 + timestamp: 1769769569681 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c md5: 18335a698559cdbcd86150a48bf54ba6 @@ -617,8 +1038,21 @@ packages: - binutils_impl_linux-64 2.45.1 license: GPL-3.0-only license_family: GPL + purls: [] size: 728002 timestamp: 1774197446916 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda + sha256: 822e4ae421a7e9c04e841323526321185f6659222325e1a9aedec811c686e688 + md5: 86f7414544ae606282352fa1e116b41f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 36544 + timestamp: 1769221884824 - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda build_number: 8 sha256: b2da6bfd72a1c9cb143ccf64bf5b28790cb4eb58bd1cb978f6537b2322f7d48b @@ -634,6 +1068,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18804 timestamp: 1779859100675 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda @@ -648,8 +1083,49 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18778 timestamp: 1779859107964 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda + sha256: 75963a5dd913311f59a35dbd307592f4fa754c4808aff9c33edb430c415e38eb + md5: c3cc2864f82a944bc90a7beb4d3b0e88 + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.22.2,<1.23.0a0 + - libgcc >=14 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 468706 + timestamp: 1777461492876 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 + md5: c277e0a4d549b03ac1e9d6cbbe3d017b + depends: + - ncurses + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 134676 + timestamp: 1738479519902 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda + sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 + md5: 172bf1cd1ff8629f2b1179945ed45055 + depends: + - libgcc-ng >=12 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 112766 + timestamp: 1702146165126 - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7 md5: 93764a5ca80616e9c10106cdaec92f74 @@ -660,6 +1136,7 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT + purls: [] size: 77294 timestamp: 1779278686680 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -670,6 +1147,7 @@ packages: - libgcc >=14 license: MIT license_family: MIT + purls: [] size: 58592 timestamp: 1769456073053 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda @@ -683,6 +1161,7 @@ packages: - libgomp 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 1041084 timestamp: 1778269013026 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda @@ -692,6 +1171,7 @@ packages: - libgcc 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 27694 timestamp: 1778269016987 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda @@ -703,6 +1183,7 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 27655 timestamp: 1778269042954 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda @@ -715,6 +1196,7 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 2483673 timestamp: 1778269025089 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda @@ -724,6 +1206,7 @@ packages: - __glibc >=2.17,<3.0.a0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 603817 timestamp: 1778268942614 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda @@ -738,6 +1221,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18790 timestamp: 1779859115086 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda @@ -749,6 +1233,7 @@ packages: constrains: - xz 5.8.3.* license: 0BSD + purls: [] size: 113478 timestamp: 1775825492909 - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda @@ -761,6 +1246,23 @@ packages: license_family: BSD size: 92400 timestamp: 1769482286018 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda + sha256: 663444d77a42f2265f54fb8b48c5450bfff4388d9c0f8253dd7855f0d993153f + md5: 2a45e7f8af083626f009645a6481f12d + depends: + - __glibc >=2.17,<3.0.a0 + - c-ares >=1.34.6,<2.0a0 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 663344 + timestamp: 1773854035739 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5 md5: d864d34357c3b65a4b731f78c0801dc4 @@ -769,6 +1271,7 @@ packages: - libgcc >=13 license: LGPL-2.1-only license_family: GPL + purls: [] size: 33731 timestamp: 1750274110928 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda @@ -783,6 +1286,7 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 5931919 timestamp: 1776993658641 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda @@ -793,8 +1297,22 @@ packages: - libgcc >=14 - libzlib >=1.3.2,<2.0a0 license: blessing + purls: [] size: 957849 timestamp: 1780574429573 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda + sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 + md5: eecce068c7e4eddeb169591baac20ac4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 304790 + timestamp: 1745608545575 - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc md5: 5794b3bdc38177caf969dabd3af08549 @@ -805,6 +1323,7 @@ packages: - libstdcxx-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 5852044 timestamp: 1778269036376 - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda @@ -815,6 +1334,7 @@ packages: - libgcc >=14 license: BSD-3-Clause license_family: BSD + purls: [] size: 40163 timestamp: 1779118517630 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda @@ -823,6 +1343,7 @@ packages: depends: - libgcc-ng >=12 license: LGPL-2.1-or-later + purls: [] size: 100393 timestamp: 1702724383534 - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda @@ -834,6 +1355,7 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other + purls: [] size: 63629 timestamp: 1774072609062 - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda @@ -843,6 +1365,7 @@ packages: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: X11 AND BSD-3-Clause + purls: [] size: 918956 timestamp: 1777422145199 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda @@ -861,6 +1384,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping size: 9389525 timestamp: 1779169198155 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -908,6 +1433,7 @@ packages: - libgcc >=14 license: Apache-2.0 license_family: Apache + purls: [] size: 3167099 timestamp: 1775587756857 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda @@ -963,6 +1489,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=compressed-mapping size: 15174736 timestamp: 1778602614189 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda @@ -1099,6 +1627,7 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 + purls: [] size: 30949404 timestamp: 1772730362552 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda @@ -1162,8 +1691,21 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL + purls: [] size: 345073 timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.7.3-hc5a330e_0.conda + sha256: 150a0a5254e8b15ad737549721c7d13406cd96432f3f446e07073dbd98bb2491 + md5: f2bd09e21c5844a12e2f5eefcd075555 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - openssl >=3.5.6,<4.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 388111 + timestamp: 1778113913631 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda sha256: 3ae2ff1d1cc5930de2ca6ac03216118bdf13b2af6098e28e827f1ba25bfcbc4e md5: 089de2ee37e4e19885c985a4fe4aaf14 @@ -1183,6 +1725,8 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 17303931 timestamp: 1779874783665 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py312h54fa4ab_1.conda @@ -1238,6 +1782,7 @@ packages: - xorg-libx11 >=1.8.12,<2.0a0 license: TCL license_family: BSD + purls: [] size: 3301196 timestamp: 1769460227866 - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -1248,6 +1793,7 @@ packages: - libzlib >=1.3.1,<2.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 601375 timestamp: 1764777111296 - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda @@ -1256,8 +1802,31 @@ packages: depends: - __unix license: ISC + purls: [] size: 129868 timestamp: 1779289852439 +- conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 + noarch: python + sha256: 561e6660f26c35d137ee150187d89767c988413c978e1b712d53f27ddf70ea17 + md5: 9b347a7ec10940d3f7941ff6c460b551 + depends: + - cached_property >=1.5.2,<1.5.3.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4134 + timestamp: 1615209571450 +- conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 + sha256: 6dbf7a5070cc43d90a1e4c2ec0c541c69d8e30a0e25f50ce9f6e4a432e42c5d7 + md5: 576d629e47797577ab0f1b351297ef4a + depends: + - python >=3.6 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/cached-property?source=hash-mapping + size: 11065 + timestamp: 1615209567874 - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 md5: 962b9857ee8e7018c22f2776ffa0b2d7 @@ -1265,6 +1834,8 @@ packages: - python >=3.9 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/colorama?source=hash-mapping size: 27011 timestamp: 1733218222191 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda @@ -1274,6 +1845,8 @@ packages: - python >=3.10 - typing_extensions >=4.6.0 license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup?source=hash-mapping size: 21333 timestamp: 1763918099466 - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda @@ -1283,6 +1856,8 @@ packages: - python >=3.10 license: MIT license_family: MIT + purls: + - pkg:pypi/iniconfig?source=hash-mapping size: 13387 timestamp: 1760831448842 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda @@ -1293,8 +1868,23 @@ packages: - python license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/packaging?source=hash-mapping size: 91574 timestamp: 1777103621679 +- conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda + sha256: 29b7d75bf81ad11645a8e320b369abdc90a92b93f2a9178e853d9dddf82e5106 + md5: 511fbc2c63d2c73650ad1755e4d357ba + depends: + - python >=3.10,<3.13.0a0 + - setuptools + - wheel + license: MIT + license_family: MIT + purls: + - pkg:pypi/pip?source=compressed-mapping + size: 1203173 + timestamp: 1780262795392 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e @@ -1303,6 +1893,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/pluggy?source=hash-mapping size: 25877 timestamp: 1764896838868 - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda @@ -1312,6 +1904,8 @@ packages: - python >=3.10 license: BSD-2-Clause license_family: BSD + purls: + - pkg:pypi/pygments?source=hash-mapping size: 893031 timestamp: 1774796815820 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda @@ -1331,6 +1925,8 @@ packages: - pytest-faulthandler >=2 license: MIT license_family: MIT + purls: + - pkg:pypi/pytest?source=hash-mapping size: 299984 timestamp: 1775644472530 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda @@ -1344,6 +1940,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/pytest-cov?source=hash-mapping size: 29559 timestamp: 1774139250481 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda @@ -1355,6 +1953,8 @@ packages: - python license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/python-dateutil?source=hash-mapping size: 233310 timestamp: 1751104122689 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda @@ -1365,6 +1965,7 @@ packages: - python 3.11.* *_cpython license: BSD-3-Clause license_family: BSD + purls: [] size: 7003 timestamp: 1752805919375 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda @@ -1387,6 +1988,17 @@ packages: license_family: BSD size: 7002 timestamp: 1752805902938 +- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + sha256: 82088a6e4daa33329a30bc26dc19a98c7c1d3f05c0f73ce9845d4eab4924e9e1 + md5: 8e194e7b992f99a5015edbd4ebd38efd + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/setuptools?source=hash-mapping + size: 639697 + timestamp: 1773074868565 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -1395,6 +2007,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/six?source=hash-mapping size: 18455 timestamp: 1753199211006 - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda @@ -1405,6 +2019,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/tomli?source=hash-mapping size: 21561 timestamp: 1774492402955 - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda @@ -1415,14 +2031,29 @@ packages: - python license: PSF-2.0 license_family: PSF + purls: + - pkg:pypi/typing-extensions?source=hash-mapping size: 51692 timestamp: 1756220668932 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c md5: ad659d0a2b3e47e38d829aa8cad2d610 license: LicenseRef-Public-Domain + purls: [] size: 119135 timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda + sha256: 9e156ffaefb8463437144326ada4b85d1de17961b9997ac5f1cbbaf747bd8bed + md5: d0e3b2f0030cf4fca58bde71d246e94c + depends: + - packaging >=24.0 + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/wheel?source=hash-mapping + size: 33491 + timestamp: 1776878563806 - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda build_number: 7 sha256: 30006902a9274de8abdad5a9f02ef7c8bb3d69a503486af0c1faee30b023e5b7 @@ -1431,8 +2062,120 @@ packages: - llvm-openmp >=9.0.1 license: BSD-3-Clause license_family: BSD + purls: [] size: 8328 timestamp: 1764092562779 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-auth-0.10.3-h2dfa1e0_2.conda + sha256: 25f88f6ab63db63ef3011084cee06c62bfadde169a630a16588b21d6969320a2 + md5: 512f46909e6c405c20728918f60851b8 + depends: + - __osx >=11.0 + - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 120720 + timestamp: 1780598468278 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-cal-0.9.14-hcb77be1_2.conda + sha256: d36ca9a9d031d381f2270480d834833e0fdb71d4793307b0a11b0ed7e45b63a0 + md5: 18708874716ed71706c80769e8ba5409 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 45674 + timestamp: 1780567082039 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-common-0.14.0-ha1e9b39_0.conda + sha256: c07dca511740b30b3bb26d9d5d14ce2577e65c422bc0afb875581792242a4514 + md5: 983f44cf7123c92ddbb19e9398f577ea + depends: + - __osx >=11.0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 232296 + timestamp: 1780161157428 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-compression-0.3.2-ha04291d_2.conda + sha256: 7e3de1e42fb88192f1e39bb3d9024d3b228ad06b94508056d0d2175448387706 + md5: a7163d39a3e639901fc1ce4865e11b47 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 21517 + timestamp: 1780566351431 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-http-0.11.0-he315c99_2.conda + sha256: 181d69666b6d7dab3669c2bf964971495c0b1dfa6a5823bf0626d8f53e1f56fb + md5: aa2b61bf50c3c666683488fef3187436 + depends: + - __osx >=11.0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-compression >=0.3.2,<0.3.3.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 197085 + timestamp: 1780586807052 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-io-0.26.3-hd35ae92_4.conda + sha256: 14903b20e23b9dbf8fc828ad1bffb46b68f1b100aee4a10beb6fbb5eb0068288 + md5: 3888bd82cc3a8f6bfa8ae0e4261b69cb + depends: + - __osx >=11.0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 182726 + timestamp: 1780575986786 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-s3-0.12.5-h8cc6e82_1.conda + sha256: 2077da563f7e81f007a4eac4b233931c8500b3ca3aae50ef37001fa90e133792 + md5: 75914204f2c708212f2185abeca539b4 + depends: + - __osx >=11.0 + - aws-c-auth >=0.10.3,<0.10.4.0a0 + - aws-checksums >=0.2.10,<0.2.11.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 135785 + timestamp: 1780609654545 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-sdkutils-0.2.4-ha04291d_6.conda + sha256: 44bca0a25e978729b995f2f265e0576d32292a4cc23953beafa233fec8f6184e + md5: 2d3f039770cab013521cc78e84b34e64 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 55961 + timestamp: 1780568586569 +- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-checksums-0.2.10-ha04291d_2.conda + sha256: 5ba7da95d95800d1fcd21397a7ddcea505faee420b2efb21b35cd12a50ad7154 + md5: 81edba692bcff370dbf8e64660097c8d + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 96023 + timestamp: 1780568602293 - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda sha256: 9f242f13537ef1ce195f93f0cc162965d6cc79da578568d6d8e50f70dd025c42 md5: 4173ac3b19ec0a4f400b4f782910368b @@ -1440,8 +2183,19 @@ packages: - __osx >=10.13 license: bzip2-1.0.6 license_family: BSD + purls: [] size: 133427 timestamp: 1771350680709 +- conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda + sha256: 2f5bc0292d595399df0d168355b4e9820affc8036792d6984bd751fdda2bcaea + md5: fc9a153c57c9f070bebaa7eef30a8f17 + depends: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: [] + size: 186122 + timestamp: 1765215100384 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda sha256: 286d4d6bf016f56d71f58c2dd495410213fb5e4053a0545d48638bfd346683bc md5: 145a45fb204a76aac34696a6fac42ece @@ -1452,6 +2206,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 396933 timestamp: 1779838320779 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py312heb39f77_0.conda @@ -1478,6 +2234,45 @@ packages: license_family: APACHE size: 395003 timestamp: 1779838290292 +- conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.16.0-nompi_py311ha7e68cf_102.conda + sha256: 0a4c211e80ffec89f568910b87790471319a59d9ab04db8e32b6d22f2eee351a + md5: f29ebc1fb2896ab15bf2712cf530e843 + depends: + - __osx >=11.0 + - cached-property + - hdf5 >=2.1.0,<3.0a0 + - numpy >=1.23,<3 + - python >=3.11,<3.12.0a0 + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/h5py?source=hash-mapping + size: 1196742 + timestamp: 1775581895921 +- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-2.1.0-nompi_h3bd5531_107.conda + sha256: 7c5d80a424d455c4bcdaf5fb8ed1851f2120beab303a2f7c531e6ac55f27f1d1 + md5: bfe98acac0bf2907f2df8907777b7b7c + depends: + - __osx >=11.0 + - aws-c-auth >=0.10.3,<0.10.4.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-s3 >=0.12.5,<0.12.6.0a0 + - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 + - libaec >=1.1.5,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 3722293 + timestamp: 1780925264460 - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda sha256: 1294117122d55246bb83ad5b589e2a031aacdf2d0b1f99fd338aa4394f881735 md5: 627eca44e62e2b665eeec57a984a7f00 @@ -1485,8 +2280,34 @@ packages: - __osx >=11.0 license: MIT license_family: MIT + purls: [] size: 12273764 timestamp: 1773822733780 +- conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda + sha256: df009385e8262c234c0dae9016540b86dad3d299f0d9366d08e327e8e7731634 + md5: e66e2c52d2fdddcf314ad750fb4ebb4a + depends: + - __osx >=10.13 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1193620 + timestamp: 1769770267475 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.5-he7c3a48_0.conda + sha256: b42ac9c684c730cb97cb3931a0a97aaf791da38bace4f6944eca10de609e5946 + md5: 975f98248cde8d54884c6d1eb5184e13 + depends: + - __osx >=10.13 + - libcxx >=19 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 30555 + timestamp: 1769222189944 - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda build_number: 8 sha256: 55cf9f92a2d07c33f8a32c44ff1528ea48fd69677cc003a4532d09b71cb8a316 @@ -1502,6 +2323,7 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 19048 timestamp: 1779860008916 - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda @@ -1516,8 +2338,25 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 19049 timestamp: 1779860025163 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.20.0-h8f0b9e4_0.conda + sha256: 5d3d8a82ca43347e96f1d79048921f3a7c25e32514bc7feb53ed2a040dcca54d + md5: 4a0085ccf90dc514f0fc0909a874045e + depends: + - __osx >=11.0 + - krb5 >=1.22.2,<1.23.0a0 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 419676 + timestamp: 1777462238769 - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda sha256: c03c298355dea54b729ed6c5f1e6dbd0e2426906039eba8aa2ba1254d005b7d8 md5: 423373b842c3861da6cfa8c8915798ce @@ -1525,8 +2364,29 @@ packages: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache + purls: [] size: 564939 timestamp: 1780442565078 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda + sha256: 6cc49785940a99e6a6b8c6edbb15f44c2dd6c789d9c283e5ee7bdfedd50b4cd6 + md5: 1f4ed31220402fcddc083b4bff406868 + depends: + - ncurses + - __osx >=10.13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 115563 + timestamp: 1738479554273 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda + sha256: 0d238488564a7992942aa165ff994eca540f687753b4f0998b29b4e4d030ff43 + md5: 899db79329439820b7e8f8de41bca902 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 106663 + timestamp: 1702146352558 - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda sha256: 460afe7ba0882e6d2fcc0ad1568dce27025110ec09c2b9ce9e3b49d61e52ce6b md5: f95dc08366f2a452005062b5bcceac51 @@ -1536,6 +2396,7 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT + purls: [] size: 75654 timestamp: 1779279058576 - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda @@ -1545,6 +2406,7 @@ packages: - __osx >=10.13 license: MIT license_family: MIT + purls: [] size: 53583 timestamp: 1769456300951 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda @@ -1557,6 +2419,7 @@ packages: - libgcc-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 424164 timestamp: 1778271183296 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda @@ -1568,6 +2431,7 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 139925 timestamp: 1778271458366 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda @@ -1579,6 +2443,7 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 1063687 timestamp: 1778271196574 - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda @@ -1593,6 +2458,7 @@ packages: - blas 2.308 openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 19030 timestamp: 1779860046842 - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda @@ -1603,6 +2469,7 @@ packages: constrains: - xz 5.8.3.* license: 0BSD + purls: [] size: 105724 timestamp: 1775826029494 - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda @@ -1614,6 +2481,22 @@ packages: license_family: BSD size: 79899 timestamp: 1769482558610 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda + sha256: 899551e16aac9dfb85bfc2fd98b655f4d1b7fea45720ec04ccb93d95b4d24798 + md5: dba4c95e2fe24adcae4b77ebf33559ae + depends: + - __osx >=11.0 + - c-ares >=1.34.6,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 606749 + timestamp: 1773854765508 - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda sha256: 2c2ffe7c3ab7becd47ad308946873d2bdc219625af32a53d10efbaa54b595d31 md5: 30666a6f0afe1471e999eca7ae5c8179 @@ -1626,6 +2509,7 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 6287889 timestamp: 1776996499823 - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda @@ -1636,8 +2520,21 @@ packages: - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing + purls: [] size: 1010419 timestamp: 1780575011758 +- conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda + sha256: 00654ba9e5f73aa1f75c1f69db34a19029e970a4aeb0fa8615934d8e9c369c3c + md5: a6cb15db1c2dc4d3a5f6cf3772e09e81 + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 284216 + timestamp: 1745608575796 - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda sha256: 4c6da089952b2d70150c74234679d6f7ac04f4a98f9432dec724968f912691e7 md5: 30439ff30578e504ee5e0b390afc8c65 @@ -1647,6 +2544,7 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other + purls: [] size: 59000 timestamp: 1774073052242 - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda @@ -1659,6 +2557,7 @@ packages: - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE + purls: [] size: 310879 timestamp: 1780456054580 - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda @@ -1667,6 +2566,7 @@ packages: depends: - __osx >=11.0 license: X11 AND BSD-3-Clause + purls: [] size: 831711 timestamp: 1777423052277 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda @@ -1684,6 +2584,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping size: 8593034 timestamp: 1779169256521 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py312h746d82c_0.conda @@ -1728,6 +2630,7 @@ packages: - ca-certificates license: Apache-2.0 license_family: Apache + purls: [] size: 2776564 timestamp: 1775589970694 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda @@ -1782,6 +2685,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14558446 timestamp: 1778602873120 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py312h8e27051_0.conda @@ -1911,6 +2816,7 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 + purls: [] size: 15664115 timestamp: 1772730794934 - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.13-ha9537fe_0_cpython.conda @@ -1965,6 +2871,7 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL + purls: [] size: 317819 timestamp: 1765813692798 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda @@ -1985,6 +2892,8 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=hash-mapping size: 15513987 timestamp: 1779875850168 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda @@ -2035,8 +2944,20 @@ packages: - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD + purls: [] size: 3282953 timestamp: 1769460532442 +- conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda + sha256: 47101a4055a70a4876ffc87b750ab2287b67eca793f21c8224be5e1ee6394d3f + md5: 727109b184d680772e3122f40136d5ca + depends: + - __osx >=10.13 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 528148 + timestamp: 1764777156963 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda build_number: 7 sha256: 7acaa2e0782cad032bdaf756b536874346ac1375745fb250e9bdd6a48a7ab3cd @@ -2045,8 +2966,120 @@ packages: - llvm-openmp >=9.0.1 license: BSD-3-Clause license_family: BSD + purls: [] size: 8325 timestamp: 1764092507920 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.10.3-hceed5df_2.conda + sha256: b4689664156e8067ba1aa97125f2a309a96b2bc0d1c608f4a88f30ea1f4c9aba + md5: e7501df14d3145fc86943ebfeb76a402 + depends: + - __osx >=11.0 + - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 116718 + timestamp: 1780598398659 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.14-h81c6212_2.conda + sha256: 557bc47cbfd01dc569b930c102cd56ca5ba67750bd51a4fcee445246e7e536cd + md5: dcac0aa854a1f7f58a59226f5309a44e + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 45764 + timestamp: 1780567235337 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-common-0.14.0-h84a0fba_0.conda + sha256: 223f67551038366555e6934802d8b375547b142157aad3fc3654c720ac1525c0 + md5: 3a49923f2b3987a833a264caca603f84 + depends: + - __osx >=11.0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 226438 + timestamp: 1780161234587 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-compression-0.3.2-h61d3404_2.conda + sha256: 4289ff476103d109623bd413b12d61307d6267e87fc6a8c29b0aec71dfa8fd84 + md5: 497edff11fcb32865d8c5d6ab3aef6e0 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 21529 + timestamp: 1780566290492 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-http-0.11.0-h0a63974_2.conda + sha256: 06d3b08ed19cd63fd75750e325f19ebf7183b22ee27cbe2ca7b7dd6725d34885 + md5: f0fc8139091eb8245209bb9ee8911a82 + depends: + - __osx >=11.0 + - aws-c-compression >=0.3.2,<0.3.3.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 177282 + timestamp: 1780586850553 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-io-0.26.3-h58c0f83_4.conda + sha256: 18f51bdc45eabe01ca68edf5ccc73369b3201639790575e6776f3efaea6e4356 + md5: b33f51eca94f6ccbd772ca4043fe1718 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 176913 + timestamp: 1780576001260 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-s3-0.12.5-h43def2a_1.conda + sha256: 0a99b506bbe21f00f21047db50b2eea2ff8a0b1146ff0fba7d04b39a568453f4 + md5: 7dc63973f9fe772985b8c2f8ba5958ce + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-checksums >=0.2.10,<0.2.11.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-auth >=0.10.3,<0.10.4.0a0 + - aws-c-cal >=0.9.14,<0.9.15.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 132141 + timestamp: 1780609600116 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-sdkutils-0.2.4-h61d3404_6.conda + sha256: ef53cd1e30bc8c865c44df6f097f36361945665157e63957d68fe90aa7e4d66c + md5: 127bce41f9e6cc3bdb9e6daed95896d9 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 53659 + timestamp: 1780568618924 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-checksums-0.2.10-h61d3404_2.conda + sha256: 9af1483700bb29870297e2390838d3c31293e8cf80fd8a8a9bd9a1446020a8d8 + md5: 7c5f6a6efce80e728c1f743e064ab657 + depends: + - __osx >=11.0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + license: Apache-2.0 + license_family: APACHE + purls: [] + size: 91975 + timestamp: 1780568646105 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda sha256: 540fe54be35fac0c17feefbdc3e29725cce05d7367ffedfaaa1bdda234b019df md5: 620b85a3f45526a8bc4d23fd78fc22f0 @@ -2054,8 +3087,19 @@ packages: - __osx >=11.0 license: bzip2-1.0.6 license_family: BSD + purls: [] size: 124834 timestamp: 1771350416561 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda + sha256: 2995f2aed4e53725e5efbc28199b46bf311c3cab2648fc4f10c2227d6d5fa196 + md5: bcb3cba70cf1eec964a03b4ba7775f01 + depends: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: [] + size: 180327 + timestamp: 1765215064054 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda sha256: d9475f473084602003da38e373604b48b674b5fbd5939eb6f26b757cbda89f28 md5: 2e3107762a2b8bb31093fe14bab1fe17 @@ -2067,6 +3111,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 397978 timestamp: 1779838426505 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py312h04c11ed_0.conda @@ -2095,6 +3141,46 @@ packages: license_family: APACHE size: 396380 timestamp: 1779838267496 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/h5py-3.16.0-nompi_py311hf10ccac_102.conda + sha256: 3d8437c0633c9055228db8d1fa00daceea5137075bdbce4bb0f7747466da0b09 + md5: 3921ef0b72feb738aa5f4107bb6bb084 + depends: + - __osx >=11.0 + - cached-property + - hdf5 >=2.1.0,<3.0a0 + - numpy >=1.23,<3 + - python >=3.11,<3.12.0a0 + - python >=3.11,<3.12.0a0 *_cpython + - python_abi 3.11.* *_cp311 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/h5py?source=hash-mapping + size: 1193405 + timestamp: 1775582985212 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-2.1.0-nompi_h9bfbf6c_107.conda + sha256: 67e9ef0dfd22a37ff51d0b19aa35e9f7da21739a624976bcac1f72ab1698e8f8 + md5: fb804a23360d2b40c4f9d15a8bf0b869 + depends: + - __osx >=11.0 + - aws-c-auth >=0.10.3,<0.10.4.0a0 + - aws-c-common >=0.14.0,<0.14.1.0a0 + - aws-c-http >=0.11.0,<0.11.1.0a0 + - aws-c-io >=0.26.3,<0.26.4.0a0 + - aws-c-s3 >=0.12.5,<0.12.6.0a0 + - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 + - libaec >=1.1.5,<2.0a0 + - libcurl >=8.20.0,<9.0a0 + - libcxx >=19 + - libgfortran + - libgfortran5 >=14.3.0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 3562608 + timestamp: 1780924273738 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda sha256: 3a7907a17e9937d3a46dfd41cffaf815abad59a569440d1e25177c15fd0684e5 md5: f1182c91c0de31a7abd40cedf6a5ebef @@ -2102,8 +3188,34 @@ packages: - __osx >=11.0 license: MIT license_family: MIT + purls: [] size: 12361647 timestamp: 1773822915649 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda + sha256: c0a0bf028fe7f3defcdcaa464e536cf1b202d07451e18ad83fdd169d15bef6ed + md5: e446e1822f4da8e5080a9de93474184d + depends: + - __osx >=11.0 + - libcxx >=19 + - libedit >=3.1.20250104,<3.2.0a0 + - libedit >=3.1.20250104,<4.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1160828 + timestamp: 1769770119811 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libaec-1.1.5-h8664d51_0.conda + sha256: af9cd8db11eb719e38a3340c88bb4882cf19b5b4237d93845224489fc2a13b46 + md5: 13e6d9ae0efbc9d2e9a01a91f4372b41 + depends: + - __osx >=11.0 + - libcxx >=19 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 30390 + timestamp: 1769222133373 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda build_number: 8 sha256: 8f5ec18ead0619a9cf0f38b49796c22f6fc0f44850c0df2baea0f5277db16e75 @@ -2119,6 +3231,7 @@ packages: - mkl <2027 license: BSD-3-Clause license_family: BSD + purls: [] size: 18949 timestamp: 1779859141315 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda @@ -2133,8 +3246,25 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18911 timestamp: 1779859147634 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda + sha256: 38c0bc634b61e542776e97cfd15d5d41edd304d4e47c333004d2d622439b2381 + md5: 2f57b7d0c6adda88957586b7afd78438 + depends: + - __osx >=11.0 + - krb5 >=1.22.2,<1.23.0a0 + - libnghttp2 >=1.68.1,<2.0a0 + - libssh2 >=1.11.1,<2.0a0 + - libzlib >=1.3.2,<2.0a0 + - openssl >=3.5.6,<4.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: curl + license_family: MIT + purls: [] + size: 400568 + timestamp: 1777462251987 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda sha256: cceb668dc1b71f054b1036dd83eca2e02c0c3a4b2ba3ad28c74a982d819597a3 md5: 0325fbe13eb6dd39234eb305ac1b3cb8 @@ -2142,8 +3272,29 @@ packages: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache + purls: [] size: 568252 timestamp: 1780441702930 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda + sha256: 66aa216a403de0bb0c1340a88d1a06adaff66bae2cfd196731aa24db9859d631 + md5: 44083d2d2c2025afca315c7a172eab2b + depends: + - ncurses + - __osx >=11.0 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 107691 + timestamp: 1738479560845 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda + sha256: 95cecb3902fbe0399c3a7e67a5bed1db813e5ab0e22f4023a5e0f722f2cc214f + md5: 36d33e440c31857372a72137f78bacf5 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 107458 + timestamp: 1702146414478 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda sha256: 3133fb6bfa871288b92c8b8752696686a841bf4ffe035aa3038033c9e15b738e md5: ef22e9ab1dc7c2f334252f565f90b3b8 @@ -2153,6 +3304,7 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT + purls: [] size: 69110 timestamp: 1779278728511 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda @@ -2162,6 +3314,7 @@ packages: - __osx >=11.0 license: MIT license_family: MIT + purls: [] size: 40979 timestamp: 1769456747661 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda @@ -2174,6 +3327,7 @@ packages: - libgomp 15.2.0 19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 404080 timestamp: 1778273064154 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda @@ -2185,6 +3339,7 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 139675 timestamp: 1778273280875 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda @@ -2196,6 +3351,7 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 599691 timestamp: 1778273075448 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda @@ -2210,6 +3366,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18925 timestamp: 1779859153970 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda @@ -2220,6 +3377,7 @@ packages: constrains: - xz 5.8.3.* license: 0BSD + purls: [] size: 92472 timestamp: 1775825802659 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda @@ -2231,6 +3389,22 @@ packages: license_family: BSD size: 73690 timestamp: 1769482560514 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda + sha256: 2bc7bc3978066f2c274ebcbf711850cc9ab92e023e433b9631958a098d11e10a + md5: 6ea18834adbc3b33df9bd9fb45eaf95b + depends: + - __osx >=11.0 + - c-ares >=1.34.6,<2.0a0 + - libcxx >=19 + - libev >=4.33,<4.34.0a0 + - libev >=4.33,<5.0a0 + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.5,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 576526 + timestamp: 1773854624224 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda sha256: 9dd455b2d172aeedfa2058d324b5b5822b0bc1b7c1f32cd183d7078540d2f6eb md5: 909e41855c29f0d52ae630198cd57135 @@ -2243,6 +3417,7 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 4304965 timestamp: 1776995497368 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda @@ -2253,8 +3428,20 @@ packages: - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing + purls: [] size: 927724 timestamp: 1780575223548 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda + sha256: 8bfe837221390ffc6f111ecca24fa12d4a6325da0c8d131333d63d6c37f27e0a + md5: b68e8f66b94b44aaa8de4583d3d4cc40 + depends: + - libzlib >=1.3.1,<2.0a0 + - openssl >=3.5.0,<4.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 279193 + timestamp: 1745608793272 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda sha256: 361415a698514b19a852f5d1123c5da746d4642139904156ddfca7c922d23a05 md5: bc5a5721b6439f2f62a84f2548136082 @@ -2264,6 +3451,7 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other + purls: [] size: 47759 timestamp: 1774072956767 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda @@ -2276,6 +3464,7 @@ packages: - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE + purls: [] size: 285162 timestamp: 1780455637760 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda @@ -2284,6 +3473,7 @@ packages: depends: - __osx >=11.0 license: X11 AND BSD-3-Clause + purls: [] size: 805509 timestamp: 1777423252320 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda @@ -2301,6 +3491,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping size: 7456206 timestamp: 1779169211856 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda @@ -2345,6 +3537,7 @@ packages: - ca-certificates license: Apache-2.0 license_family: Apache + purls: [] size: 3106008 timestamp: 1775587972483 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda @@ -2400,6 +3593,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14329411 timestamp: 1778602822615 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py312h6510ced_0.conda @@ -2531,6 +3726,7 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 + purls: [] size: 14753109 timestamp: 1772730203101 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.13-h8561d8f_0_cpython.conda @@ -2585,6 +3781,7 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL + purls: [] size: 313930 timestamp: 1765813902568 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda @@ -2605,6 +3802,8 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 13954661 timestamp: 1779874558902 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda @@ -2655,5 +3854,20 @@ packages: - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD + purls: [] size: 3127137 timestamp: 1769460817696 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda + sha256: 9485ba49e8f47d2b597dd399e88f4802e100851b27c21d7525625b0b4025a5d9 + md5: ab136e4c34e97f34fb621d2592a393d8 + depends: + - __osx >=11.0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 433413 + timestamp: 1764777166076 +- pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd + name: cmlreaders + version: 0.12.2 diff --git a/pixi.toml b/pixi.toml index 6ebb640..1012b9c 100644 --- a/pixi.toml +++ b/pixi.toml @@ -21,11 +21,27 @@ python = "3.12.*" [feature.py313.dependencies] python = "3.13.*" +# Real-data integration env: cmlreaders to read ltpFR2 behavioral events off +# rhino. Only usable on a host with the /protocols/ltp mount; the real-data +# tests skip cleanly elsewhere. cmlreaders is not on PyPI, so install from git. +[feature.rhino.dependencies] +python = "3.11.*" +h5py = "*" +setuptools = "*" +pip = "*" +[feature.rhino.pypi-dependencies] +cmlreaders = { git = "https://github.com/pennmem/cmlreaders.git" } +# cmlreaders' setup.py imports pandas at build time; build against the env's +# already-installed conda numpy/pandas rather than an isolated build env. +[feature.rhino.pypi-options] +no-build-isolation = ["cmlreaders"] + [environments] default = ["test"] py311 = ["py311", "test"] py312 = ["py312", "test"] py313 = ["py313", "test"] +rhino = ["rhino", "test"] [tasks] # Pure-Python package: no compiled extensions to build. This task is the diff --git a/tests/test_real_data.py b/tests/test_real_data.py index 4a8a7a5..8f726ca 100644 --- a/tests/test_real_data.py +++ b/tests/test_real_data.py @@ -81,22 +81,25 @@ def test_pd_crp_contiguity_and_asymmetry(ltpfr2): # --- temporal clustering factor: above chance -------------------------------- -def test_pd_crp_matches_groupby_apply_convention(ltpfr2): +def test_pd_crp_matches_per_subject_decomposition(ltpfr2): """The canonical usage (FR1_analyses.ipynb cell 10) is - ``events.groupby('subject').apply(pb.pd_crp, itemno_column='item_num')``. - For a single subject that must equal the direct per-subject call, confirming - we drive pybeh_pd the way the lab's notebooks do.""" - import warnings + ``events.groupby('subject').apply(pb.pd_crp, itemno_column='item_num')``, + i.e. pd_crp applied independently to each subject's events. Confirm the direct + call on a single subject's frame equals that per-subject decomposition. + + NB the literal ``groupby(...).apply(...)`` idiom from the notebooks breaks on + pandas >= 3 (the grouping column 'subject', which pd_crp needs via + ``list_index``, is now dropped from the applied frame). We express the + decomposition by explicit slicing so the equivalence holds on pandas 2 and 3; + the notebook idiom itself is tracked as a pandas-3 compat item in bug_report.md. + """ direct = pb.pd_crp(ltpfr2, itemno_column=ITEMNO).sort_values("lag")["prob"].values - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - grouped = ( - ltpfr2.groupby("subject") - .apply(pb.pd_crp, itemno_column=ITEMNO) - .reset_index() - ) - via = grouped.sort_values("lag")["prob"].values - assert np.allclose(direct, via, equal_nan=True) + per_subject = [ + pb.pd_crp(g, itemno_column=ITEMNO).sort_values("lag")["prob"].values + for _, g in ltpfr2.groupby("subject") + ] + assert len(per_subject) == 1 # this fixture is one subject + assert np.allclose(direct, per_subject[0], equal_nan=True) def test_pd_temp_fact_above_chance(ltpfr2): From 9016b9394e8df72495b1c6a0b454ed89733b854d Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 02:00:36 +0000 Subject: [PATCH 09/15] test: self-contained ltpFR2 fixture + comprehensive real-data golden Commit 5 sessions of ltpFR2 (LTP093) behavioral events as tests/data/ ltpfr2_5sessions.csv plus frozen pybeh_pd outputs (ltpfr2_golden.npz), so the real-data integration tests run anywhere without cmlreaders or the rhino mount. Drops the pixi rhino env. The golden comprehensively locks every analysis applicable to plain free-recall events (matrix builders, full lag-CRP family incl. min_crp, temporal factor incl. min_temp_fact, pooled and per-session) via a capture_outputs() shared by the test and the regeneration script; semantic CRP / distance-factor stay locked on the synthetic suite (ltpFR2 has no semantic space). 216 tests pass on numpy 1.24/pandas 2.3 and numpy 2.4/pandas 3.0. --- pixi.lock | 1214 --------- pixi.toml | 16 - pytest.ini | 1 - tests/data/_regenerate_ltpfr2.py | 61 + tests/data/ltpfr2_5sessions.csv | 4250 ++++++++++++++++++++++++++++++ tests/data/ltpfr2_golden.npz | Bin 0 -> 114244 bytes tests/real_data.py | 123 +- tests/test_real_data.py | 156 +- 8 files changed, 4458 insertions(+), 1363 deletions(-) create mode 100644 tests/data/_regenerate_ltpfr2.py create mode 100644 tests/data/ltpfr2_5sessions.csv create mode 100644 tests/data/ltpfr2_golden.npz diff --git a/pixi.lock b/pixi.lock index eca3d85..88aef25 100644 --- a/pixi.lock +++ b/pixi.lock @@ -544,222 +544,6 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - rhino: - channels: - - url: https://conda.anaconda.org/conda-forge/ - indexes: - - https://pypi.org/simple - packages: - linux-64: - - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.10.3-hea842a7_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.14-h78948cc_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.14.0-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.2-haa0cbde_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.11.0-h6488f85_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.26.3-h5b668fc_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.12.5-hb916526_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.4-haa0cbde_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.10-haa0cbde_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311hfef529e_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-2.1.0-nompi_h735b18d_107.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.7.3-hc5a330e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - - pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd - osx-64: - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-auth-0.10.3-h2dfa1e0_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-cal-0.9.14-hcb77be1_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-common-0.14.0-ha1e9b39_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-compression-0.3.2-ha04291d_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-http-0.11.0-he315c99_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-io-0.26.3-hd35ae92_4.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-s3-0.12.5-h8cc6e82_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-sdkutils-0.2.4-ha04291d_6.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/aws-checksums-0.2.10-ha04291d_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.16.0-nompi_py311ha7e68cf_102.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-2.1.0-nompi_h3bd5531_107.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.5-he7c3a48_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.20.0-h8f0b9e4_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.15-ha9537fe_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda - - conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda - - pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd - osx-arm64: - - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.10.3-hceed5df_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.14-h81c6212_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-common-0.14.0-h84a0fba_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-compression-0.3.2-h61d3404_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-http-0.11.0-h0a63974_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-io-0.26.3-h58c0f83_4.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-s3-0.12.5-h43def2a_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-sdkutils-0.2.4-h61d3404_6.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-checksums-0.2.10-h61d3404_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/h5py-3.16.0-nompi_py311hf10ccac_102.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-2.1.0-nompi_h9bfbf6c_107.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libaec-1.1.5-h8664d51_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.15-h8561d8f_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - - conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - - pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda build_number: 20 @@ -772,132 +556,8 @@ packages: - openmp_impl <0.0a0 license: BSD-3-Clause license_family: BSD - purls: [] size: 28948 timestamp: 1770939786096 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.10.3-hea842a7_2.conda - sha256: 5b9c20a38fe084b4ffd1f2c64b3797ec6ef9a99e83cc0c1f84e016c9801e3a5c - md5: c463d2dbfb12a208c943165d2a568db4 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 134385 - timestamp: 1780598328124 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.14-h78948cc_2.conda - sha256: 06a0e2af439b21c94adff8fac5dd66dbda5f182fc80ac635c4903959ea306cbb - md5: fe81235aae00f32df8584267b4f2daf8 - depends: - - __glibc >=2.17,<3.0.a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - libgcc >=14 - - openssl >=3.5.6,<4.0a0 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 57011 - timestamp: 1780566647051 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.14.0-hb03c661_0.conda - sha256: 6d2b33965bf6daeffd3ad336f41410053ff06ed6f2b2ce62c1ec27c0a39b4e7e - md5: f1c005b2e3b618706112ddd7f3af4521 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 242497 - timestamp: 1780160843944 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.2-haa0cbde_2.conda - sha256: 0e4952f9be8de7f281ca7d734a3a8f05ad0db856c6ef1e0897798c4afbcd9a54 - md5: 595911421e25551e36fde7027bf33f38 - depends: - - libgcc >=14 - - __glibc >=2.17,<3.0.a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 22007 - timestamp: 1780566239465 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.11.0-h6488f85_2.conda - sha256: d2b844db1a4dfbc20b5129b7df4a656c1459c5fb16745101bbd802813ba8d411 - md5: da0be1e8cb4a43c876f26d9d812dea06 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - aws-c-compression >=0.3.2,<0.3.3.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 230293 - timestamp: 1780586764553 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.26.3-h5b668fc_4.conda - sha256: c27b972325342f062da00b7aa2d5abf6f3ce55668a05703a175be958745cc226 - md5: 555400dce62f2d989ff77761c010d166 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - s2n >=1.7.3,<1.7.4.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 181627 - timestamp: 1780575920109 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.12.5-hb916526_1.conda - sha256: 8f193173f1dccb25ff86a95543db27f0c762cccfe93157b02cf20bd5b4c11a92 - md5: 70bc8e5e8cefd19407423733e7ebf540 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - aws-checksums >=0.2.10,<0.2.11.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - - openssl >=3.5.6,<4.0a0 - - aws-c-auth >=0.10.3,<0.10.4.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 153453 - timestamp: 1780609553521 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.4-haa0cbde_6.conda - sha256: 123c4325b16f1f6db95846d51e5e4201399ee29c0325f8b5a8db2e7d732b9151 - md5: 4b66ac29a7e917a629b790c3d239d110 - depends: - - libgcc >=14 - - __glibc >=2.17,<3.0.a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 59085 - timestamp: 1780568538653 -- conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.10-haa0cbde_2.conda - sha256: ad49333d96a5f9bcce02752a6515cbb077d7513e358a8fb1a832f4e772d54bac - md5: 5c05a63452bf73c50aa272a6f961c4fc - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 101627 - timestamp: 1780568539000 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda sha256: 0b75d45f0bba3e95dc693336fa51f40ea28c980131fec438afb7ce6118ed05f6 md5: d2ffd7602c02f2b316fd921d39876885 @@ -906,20 +566,8 @@ packages: - libgcc >=14 license: bzip2-1.0.6 license_family: BSD - purls: [] size: 260182 timestamp: 1771350215188 -- conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda - sha256: cc9accf72fa028d31c2a038460787751127317dcfa991f8d1f1babf216bb454e - md5: 920bb03579f15389b9e512095ad995b7 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - license: MIT - license_family: MIT - purls: [] - size: 207882 - timestamp: 1765214722852 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda sha256: ebefe7c8a41d14e4a50c5b862cf0226b3ac745495415bb6fb0db364b945cfe3a md5: f875c239f662e1b31fbf32282f1da087 @@ -931,8 +579,6 @@ packages: - tomli license: Apache-2.0 license_family: APACHE - purls: - - pkg:pypi/coverage?source=hash-mapping size: 399156 timestamp: 1779838054673 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py312h8a5da7c_0.conda @@ -961,73 +607,6 @@ packages: license_family: APACHE size: 396489 timestamp: 1779837909103 -- conda: https://conda.anaconda.org/conda-forge/linux-64/h5py-3.16.0-nompi_py311hfef529e_102.conda - sha256: 9495b6fe2a7b1cf0fded3c53252e964d968fa1fc87cf1ce76c4d9c5e8ab22385 - md5: 5737f2130791c91aee8374ee0d4465de - depends: - - __glibc >=2.17,<3.0.a0 - - cached-property - - hdf5 >=2.1.0,<3.0a0 - - libgcc >=14 - - numpy >=1.23,<3 - - python >=3.11,<3.12.0a0 - - python_abi 3.11.* *_cp311 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/h5py?source=hash-mapping - size: 1359434 - timestamp: 1775581283533 -- conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-2.1.0-nompi_h735b18d_107.conda - sha256: ff8336394dcfaccf49e56d1dd66091cf767df0d3d33f3fa440c980e0445b34cc - md5: b1b444bca8da3ff6cc4afad1fa7f7d61 - depends: - - __glibc >=2.17,<3.0.a0 - - aws-c-auth >=0.10.3,<0.10.4.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-s3 >=0.12.5,<0.12.6.0a0 - - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 - - libaec >=1.1.5,<2.0a0 - - libcurl >=8.20.0,<9.0a0 - - libgcc >=14 - - libgfortran - - libgfortran5 >=14.3.0 - - libstdcxx >=14 - - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.6,<4.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 4610890 - timestamp: 1780923415022 -- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda - sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 - md5: b38117a3c920364aff79f870c984b4a3 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - license: LGPL-2.1-or-later - purls: [] - size: 134088 - timestamp: 1754905959823 -- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda - sha256: 3e307628ca3527448dd1cb14ad7bb9d04d1d28c7d4c5f97ba196ae984571dd25 - md5: fb53fb07ce46a575c5d004bbc96032c2 - depends: - - __glibc >=2.17,<3.0.a0 - - keyutils >=1.6.3,<2.0a0 - - libedit >=3.1.20250104,<3.2.0a0 - - libedit >=3.1.20250104,<4.0a0 - - libgcc >=14 - - libstdcxx >=14 - - openssl >=3.5.5,<4.0a0 - license: MIT - license_family: MIT - purls: [] - size: 1386730 - timestamp: 1769769569681 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda sha256: 3d584956604909ff5df353767f3a2a2f60e07d070b328d109f30ac40cd62df6c md5: 18335a698559cdbcd86150a48bf54ba6 @@ -1038,21 +617,8 @@ packages: - binutils_impl_linux-64 2.45.1 license: GPL-3.0-only license_family: GPL - purls: [] size: 728002 timestamp: 1774197446916 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda - sha256: 822e4ae421a7e9c04e841323526321185f6659222325e1a9aedec811c686e688 - md5: 86f7414544ae606282352fa1e116b41f - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - libstdcxx >=14 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 36544 - timestamp: 1769221884824 - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda build_number: 8 sha256: b2da6bfd72a1c9cb143ccf64bf5b28790cb4eb58bd1cb978f6537b2322f7d48b @@ -1068,7 +634,6 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 18804 timestamp: 1779859100675 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda @@ -1083,49 +648,8 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 18778 timestamp: 1779859107964 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.20.0-hcf29cc6_0.conda - sha256: 75963a5dd913311f59a35dbd307592f4fa754c4808aff9c33edb430c415e38eb - md5: c3cc2864f82a944bc90a7beb4d3b0e88 - depends: - - __glibc >=2.17,<3.0.a0 - - krb5 >=1.22.2,<1.23.0a0 - - libgcc >=14 - - libnghttp2 >=1.68.1,<2.0a0 - - libssh2 >=1.11.1,<2.0a0 - - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.6,<4.0a0 - - zstd >=1.5.7,<1.6.0a0 - license: curl - license_family: MIT - purls: [] - size: 468706 - timestamp: 1777461492876 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda - sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 - md5: c277e0a4d549b03ac1e9d6cbbe3d017b - depends: - - ncurses - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - ncurses >=6.5,<7.0a0 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 134676 - timestamp: 1738479519902 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 - md5: 172bf1cd1ff8629f2b1179945ed45055 - depends: - - libgcc-ng >=12 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 112766 - timestamp: 1702146165126 - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda sha256: 363018b25fdb5534c79783d912bd4b685a3547f4fc5996357ad548899b0ee8e7 md5: 93764a5ca80616e9c10106cdaec92f74 @@ -1136,7 +660,6 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT - purls: [] size: 77294 timestamp: 1779278686680 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -1147,7 +670,6 @@ packages: - libgcc >=14 license: MIT license_family: MIT - purls: [] size: 58592 timestamp: 1769456073053 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda @@ -1161,7 +683,6 @@ packages: - libgomp 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 1041084 timestamp: 1778269013026 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda @@ -1171,7 +692,6 @@ packages: - libgcc 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 27694 timestamp: 1778269016987 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda @@ -1183,7 +703,6 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 27655 timestamp: 1778269042954 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda @@ -1196,7 +715,6 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 2483673 timestamp: 1778269025089 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda @@ -1206,7 +724,6 @@ packages: - __glibc >=2.17,<3.0.a0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 603817 timestamp: 1778268942614 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda @@ -1221,7 +738,6 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 18790 timestamp: 1779859115086 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda @@ -1233,7 +749,6 @@ packages: constrains: - xz 5.8.3.* license: 0BSD - purls: [] size: 113478 timestamp: 1775825492909 - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda @@ -1246,23 +761,6 @@ packages: license_family: BSD size: 92400 timestamp: 1769482286018 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.68.1-h877daf1_0.conda - sha256: 663444d77a42f2265f54fb8b48c5450bfff4388d9c0f8253dd7855f0d993153f - md5: 2a45e7f8af083626f009645a6481f12d - depends: - - __glibc >=2.17,<3.0.a0 - - c-ares >=1.34.6,<2.0a0 - - libev >=4.33,<4.34.0a0 - - libev >=4.33,<5.0a0 - - libgcc >=14 - - libstdcxx >=14 - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.5,<4.0a0 - license: MIT - license_family: MIT - purls: [] - size: 663344 - timestamp: 1773854035739 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda sha256: 927fe72b054277cde6cb82597d0fcf6baf127dcbce2e0a9d8925a68f1265eef5 md5: d864d34357c3b65a4b731f78c0801dc4 @@ -1271,7 +769,6 @@ packages: - libgcc >=13 license: LGPL-2.1-only license_family: GPL - purls: [] size: 33731 timestamp: 1750274110928 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda @@ -1286,7 +783,6 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD - purls: [] size: 5931919 timestamp: 1776993658641 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda @@ -1297,22 +793,8 @@ packages: - libgcc >=14 - libzlib >=1.3.2,<2.0a0 license: blessing - purls: [] size: 957849 timestamp: 1780574429573 -- conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda - sha256: fa39bfd69228a13e553bd24601332b7cfeb30ca11a3ca50bb028108fe90a7661 - md5: eecce068c7e4eddeb169591baac20ac4 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=13 - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.0,<4.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 304790 - timestamp: 1745608545575 - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda sha256: dff1058c76ec6b8759e41cefa2508162d00e4a5e6721aa68ec3fd10094e702dc md5: 5794b3bdc38177caf969dabd3af08549 @@ -1323,7 +805,6 @@ packages: - libstdcxx-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 5852044 timestamp: 1778269036376 - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda @@ -1334,7 +815,6 @@ packages: - libgcc >=14 license: BSD-3-Clause license_family: BSD - purls: [] size: 40163 timestamp: 1779118517630 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda @@ -1343,7 +823,6 @@ packages: depends: - libgcc-ng >=12 license: LGPL-2.1-or-later - purls: [] size: 100393 timestamp: 1702724383534 - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda @@ -1355,7 +834,6 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other - purls: [] size: 63629 timestamp: 1774072609062 - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda @@ -1365,7 +843,6 @@ packages: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: X11 AND BSD-3-Clause - purls: [] size: 918956 timestamp: 1777422145199 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda @@ -1384,8 +861,6 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/numpy?source=compressed-mapping size: 9389525 timestamp: 1779169198155 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -1433,7 +908,6 @@ packages: - libgcc >=14 license: Apache-2.0 license_family: Apache - purls: [] size: 3167099 timestamp: 1775587756857 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda @@ -1489,8 +963,6 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/pandas?source=compressed-mapping size: 15174736 timestamp: 1778602614189 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda @@ -1627,7 +1099,6 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 - purls: [] size: 30949404 timestamp: 1772730362552 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda @@ -1691,21 +1162,8 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL - purls: [] size: 345073 timestamp: 1765813471974 -- conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.7.3-hc5a330e_0.conda - sha256: 150a0a5254e8b15ad737549721c7d13406cd96432f3f446e07073dbd98bb2491 - md5: f2bd09e21c5844a12e2f5eefcd075555 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc >=14 - - openssl >=3.5.6,<4.0a0 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 388111 - timestamp: 1778113913631 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda sha256: 3ae2ff1d1cc5930de2ca6ac03216118bdf13b2af6098e28e827f1ba25bfcbc4e md5: 089de2ee37e4e19885c985a4fe4aaf14 @@ -1725,8 +1183,6 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/scipy?source=compressed-mapping size: 17303931 timestamp: 1779874783665 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py312h54fa4ab_1.conda @@ -1782,7 +1238,6 @@ packages: - xorg-libx11 >=1.8.12,<2.0a0 license: TCL license_family: BSD - purls: [] size: 3301196 timestamp: 1769460227866 - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -1793,7 +1248,6 @@ packages: - libzlib >=1.3.1,<2.0a0 license: BSD-3-Clause license_family: BSD - purls: [] size: 601375 timestamp: 1764777111296 - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda @@ -1802,31 +1256,8 @@ packages: depends: - __unix license: ISC - purls: [] size: 129868 timestamp: 1779289852439 -- conda: https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2 - noarch: python - sha256: 561e6660f26c35d137ee150187d89767c988413c978e1b712d53f27ddf70ea17 - md5: 9b347a7ec10940d3f7941ff6c460b551 - depends: - - cached_property >=1.5.2,<1.5.3.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 4134 - timestamp: 1615209571450 -- conda: https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2 - sha256: 6dbf7a5070cc43d90a1e4c2ec0c541c69d8e30a0e25f50ce9f6e4a432e42c5d7 - md5: 576d629e47797577ab0f1b351297ef4a - depends: - - python >=3.6 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/cached-property?source=hash-mapping - size: 11065 - timestamp: 1615209567874 - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 md5: 962b9857ee8e7018c22f2776ffa0b2d7 @@ -1834,8 +1265,6 @@ packages: - python >=3.9 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/colorama?source=hash-mapping size: 27011 timestamp: 1733218222191 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda @@ -1845,8 +1274,6 @@ packages: - python >=3.10 - typing_extensions >=4.6.0 license: MIT and PSF-2.0 - purls: - - pkg:pypi/exceptiongroup?source=hash-mapping size: 21333 timestamp: 1763918099466 - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda @@ -1856,8 +1283,6 @@ packages: - python >=3.10 license: MIT license_family: MIT - purls: - - pkg:pypi/iniconfig?source=hash-mapping size: 13387 timestamp: 1760831448842 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda @@ -1868,23 +1293,8 @@ packages: - python license: Apache-2.0 license_family: APACHE - purls: - - pkg:pypi/packaging?source=hash-mapping size: 91574 timestamp: 1777103621679 -- conda: https://conda.anaconda.org/conda-forge/noarch/pip-26.1.2-pyh8b19718_0.conda - sha256: 29b7d75bf81ad11645a8e320b369abdc90a92b93f2a9178e853d9dddf82e5106 - md5: 511fbc2c63d2c73650ad1755e4d357ba - depends: - - python >=3.10,<3.13.0a0 - - setuptools - - wheel - license: MIT - license_family: MIT - purls: - - pkg:pypi/pip?source=compressed-mapping - size: 1203173 - timestamp: 1780262795392 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e @@ -1893,8 +1303,6 @@ packages: - python license: MIT license_family: MIT - purls: - - pkg:pypi/pluggy?source=hash-mapping size: 25877 timestamp: 1764896838868 - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda @@ -1904,8 +1312,6 @@ packages: - python >=3.10 license: BSD-2-Clause license_family: BSD - purls: - - pkg:pypi/pygments?source=hash-mapping size: 893031 timestamp: 1774796815820 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda @@ -1925,8 +1331,6 @@ packages: - pytest-faulthandler >=2 license: MIT license_family: MIT - purls: - - pkg:pypi/pytest?source=hash-mapping size: 299984 timestamp: 1775644472530 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda @@ -1940,8 +1344,6 @@ packages: - python license: MIT license_family: MIT - purls: - - pkg:pypi/pytest-cov?source=hash-mapping size: 29559 timestamp: 1774139250481 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda @@ -1953,8 +1355,6 @@ packages: - python license: Apache-2.0 license_family: APACHE - purls: - - pkg:pypi/python-dateutil?source=hash-mapping size: 233310 timestamp: 1751104122689 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda @@ -1965,7 +1365,6 @@ packages: - python 3.11.* *_cpython license: BSD-3-Clause license_family: BSD - purls: [] size: 7003 timestamp: 1752805919375 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda @@ -1988,17 +1387,6 @@ packages: license_family: BSD size: 7002 timestamp: 1752805902938 -- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda - sha256: 82088a6e4daa33329a30bc26dc19a98c7c1d3f05c0f73ce9845d4eab4924e9e1 - md5: 8e194e7b992f99a5015edbd4ebd38efd - depends: - - python >=3.10 - license: MIT - license_family: MIT - purls: - - pkg:pypi/setuptools?source=hash-mapping - size: 639697 - timestamp: 1773074868565 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -2007,8 +1395,6 @@ packages: - python license: MIT license_family: MIT - purls: - - pkg:pypi/six?source=hash-mapping size: 18455 timestamp: 1753199211006 - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda @@ -2019,8 +1405,6 @@ packages: - python license: MIT license_family: MIT - purls: - - pkg:pypi/tomli?source=hash-mapping size: 21561 timestamp: 1774492402955 - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda @@ -2031,29 +1415,14 @@ packages: - python license: PSF-2.0 license_family: PSF - purls: - - pkg:pypi/typing-extensions?source=hash-mapping size: 51692 timestamp: 1756220668932 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c md5: ad659d0a2b3e47e38d829aa8cad2d610 license: LicenseRef-Public-Domain - purls: [] size: 119135 timestamp: 1767016325805 -- conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.47.0-pyhd8ed1ab_0.conda - sha256: 9e156ffaefb8463437144326ada4b85d1de17961b9997ac5f1cbbaf747bd8bed - md5: d0e3b2f0030cf4fca58bde71d246e94c - depends: - - packaging >=24.0 - - python >=3.10 - license: MIT - license_family: MIT - purls: - - pkg:pypi/wheel?source=hash-mapping - size: 33491 - timestamp: 1776878563806 - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda build_number: 7 sha256: 30006902a9274de8abdad5a9f02ef7c8bb3d69a503486af0c1faee30b023e5b7 @@ -2062,120 +1431,8 @@ packages: - llvm-openmp >=9.0.1 license: BSD-3-Clause license_family: BSD - purls: [] size: 8328 timestamp: 1764092562779 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-auth-0.10.3-h2dfa1e0_2.conda - sha256: 25f88f6ab63db63ef3011084cee06c62bfadde169a630a16588b21d6969320a2 - md5: 512f46909e6c405c20728918f60851b8 - depends: - - __osx >=11.0 - - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 120720 - timestamp: 1780598468278 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-cal-0.9.14-hcb77be1_2.conda - sha256: d36ca9a9d031d381f2270480d834833e0fdb71d4793307b0a11b0ed7e45b63a0 - md5: 18708874716ed71706c80769e8ba5409 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 45674 - timestamp: 1780567082039 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-common-0.14.0-ha1e9b39_0.conda - sha256: c07dca511740b30b3bb26d9d5d14ce2577e65c422bc0afb875581792242a4514 - md5: 983f44cf7123c92ddbb19e9398f577ea - depends: - - __osx >=11.0 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 232296 - timestamp: 1780161157428 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-compression-0.3.2-ha04291d_2.conda - sha256: 7e3de1e42fb88192f1e39bb3d9024d3b228ad06b94508056d0d2175448387706 - md5: a7163d39a3e639901fc1ce4865e11b47 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 21517 - timestamp: 1780566351431 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-http-0.11.0-he315c99_2.conda - sha256: 181d69666b6d7dab3669c2bf964971495c0b1dfa6a5823bf0626d8f53e1f56fb - md5: aa2b61bf50c3c666683488fef3187436 - depends: - - __osx >=11.0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-compression >=0.3.2,<0.3.3.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 197085 - timestamp: 1780586807052 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-io-0.26.3-hd35ae92_4.conda - sha256: 14903b20e23b9dbf8fc828ad1bffb46b68f1b100aee4a10beb6fbb5eb0068288 - md5: 3888bd82cc3a8f6bfa8ae0e4261b69cb - depends: - - __osx >=11.0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 182726 - timestamp: 1780575986786 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-s3-0.12.5-h8cc6e82_1.conda - sha256: 2077da563f7e81f007a4eac4b233931c8500b3ca3aae50ef37001fa90e133792 - md5: 75914204f2c708212f2185abeca539b4 - depends: - - __osx >=11.0 - - aws-c-auth >=0.10.3,<0.10.4.0a0 - - aws-checksums >=0.2.10,<0.2.11.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 135785 - timestamp: 1780609654545 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-c-sdkutils-0.2.4-ha04291d_6.conda - sha256: 44bca0a25e978729b995f2f265e0576d32292a4cc23953beafa233fec8f6184e - md5: 2d3f039770cab013521cc78e84b34e64 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 55961 - timestamp: 1780568586569 -- conda: https://conda.anaconda.org/conda-forge/osx-64/aws-checksums-0.2.10-ha04291d_2.conda - sha256: 5ba7da95d95800d1fcd21397a7ddcea505faee420b2efb21b35cd12a50ad7154 - md5: 81edba692bcff370dbf8e64660097c8d - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 96023 - timestamp: 1780568602293 - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda sha256: 9f242f13537ef1ce195f93f0cc162965d6cc79da578568d6d8e50f70dd025c42 md5: 4173ac3b19ec0a4f400b4f782910368b @@ -2183,19 +1440,8 @@ packages: - __osx >=10.13 license: bzip2-1.0.6 license_family: BSD - purls: [] size: 133427 timestamp: 1771350680709 -- conda: https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.34.6-hb5e19a0_0.conda - sha256: 2f5bc0292d595399df0d168355b4e9820affc8036792d6984bd751fdda2bcaea - md5: fc9a153c57c9f070bebaa7eef30a8f17 - depends: - - __osx >=10.13 - license: MIT - license_family: MIT - purls: [] - size: 186122 - timestamp: 1765215100384 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda sha256: 286d4d6bf016f56d71f58c2dd495410213fb5e4053a0545d48638bfd346683bc md5: 145a45fb204a76aac34696a6fac42ece @@ -2206,8 +1452,6 @@ packages: - tomli license: Apache-2.0 license_family: APACHE - purls: - - pkg:pypi/coverage?source=hash-mapping size: 396933 timestamp: 1779838320779 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py312heb39f77_0.conda @@ -2234,45 +1478,6 @@ packages: license_family: APACHE size: 395003 timestamp: 1779838290292 -- conda: https://conda.anaconda.org/conda-forge/osx-64/h5py-3.16.0-nompi_py311ha7e68cf_102.conda - sha256: 0a4c211e80ffec89f568910b87790471319a59d9ab04db8e32b6d22f2eee351a - md5: f29ebc1fb2896ab15bf2712cf530e843 - depends: - - __osx >=11.0 - - cached-property - - hdf5 >=2.1.0,<3.0a0 - - numpy >=1.23,<3 - - python >=3.11,<3.12.0a0 - - python_abi 3.11.* *_cp311 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/h5py?source=hash-mapping - size: 1196742 - timestamp: 1775581895921 -- conda: https://conda.anaconda.org/conda-forge/osx-64/hdf5-2.1.0-nompi_h3bd5531_107.conda - sha256: 7c5d80a424d455c4bcdaf5fb8ed1851f2120beab303a2f7c531e6ac55f27f1d1 - md5: bfe98acac0bf2907f2df8907777b7b7c - depends: - - __osx >=11.0 - - aws-c-auth >=0.10.3,<0.10.4.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-s3 >=0.12.5,<0.12.6.0a0 - - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 - - libaec >=1.1.5,<2.0a0 - - libcurl >=8.20.0,<9.0a0 - - libcxx >=19 - - libgfortran - - libgfortran5 >=14.3.0 - - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.6,<4.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 3722293 - timestamp: 1780925264460 - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda sha256: 1294117122d55246bb83ad5b589e2a031aacdf2d0b1f99fd338aa4394f881735 md5: 627eca44e62e2b665eeec57a984a7f00 @@ -2280,34 +1485,8 @@ packages: - __osx >=11.0 license: MIT license_family: MIT - purls: [] size: 12273764 timestamp: 1773822733780 -- conda: https://conda.anaconda.org/conda-forge/osx-64/krb5-1.22.2-h207b36a_0.conda - sha256: df009385e8262c234c0dae9016540b86dad3d299f0d9366d08e327e8e7731634 - md5: e66e2c52d2fdddcf314ad750fb4ebb4a - depends: - - __osx >=10.13 - - libcxx >=19 - - libedit >=3.1.20250104,<3.2.0a0 - - libedit >=3.1.20250104,<4.0a0 - - openssl >=3.5.5,<4.0a0 - license: MIT - license_family: MIT - purls: [] - size: 1193620 - timestamp: 1769770267475 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libaec-1.1.5-he7c3a48_0.conda - sha256: b42ac9c684c730cb97cb3931a0a97aaf791da38bace4f6944eca10de609e5946 - md5: 975f98248cde8d54884c6d1eb5184e13 - depends: - - __osx >=10.13 - - libcxx >=19 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 30555 - timestamp: 1769222189944 - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda build_number: 8 sha256: 55cf9f92a2d07c33f8a32c44ff1528ea48fd69677cc003a4532d09b71cb8a316 @@ -2323,7 +1502,6 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 19048 timestamp: 1779860008916 - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda @@ -2338,25 +1516,8 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 19049 timestamp: 1779860025163 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libcurl-8.20.0-h8f0b9e4_0.conda - sha256: 5d3d8a82ca43347e96f1d79048921f3a7c25e32514bc7feb53ed2a040dcca54d - md5: 4a0085ccf90dc514f0fc0909a874045e - depends: - - __osx >=11.0 - - krb5 >=1.22.2,<1.23.0a0 - - libnghttp2 >=1.68.1,<2.0a0 - - libssh2 >=1.11.1,<2.0a0 - - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.6,<4.0a0 - - zstd >=1.5.7,<1.6.0a0 - license: curl - license_family: MIT - purls: [] - size: 419676 - timestamp: 1777462238769 - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda sha256: c03c298355dea54b729ed6c5f1e6dbd0e2426906039eba8aa2ba1254d005b7d8 md5: 423373b842c3861da6cfa8c8915798ce @@ -2364,29 +1525,8 @@ packages: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - purls: [] size: 564939 timestamp: 1780442565078 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20250104-pl5321ha958ccf_0.conda - sha256: 6cc49785940a99e6a6b8c6edbb15f44c2dd6c789d9c283e5ee7bdfedd50b4cd6 - md5: 1f4ed31220402fcddc083b4bff406868 - depends: - - ncurses - - __osx >=10.13 - - ncurses >=6.5,<7.0a0 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 115563 - timestamp: 1738479554273 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-h10d778d_2.conda - sha256: 0d238488564a7992942aa165ff994eca540f687753b4f0998b29b4e4d030ff43 - md5: 899db79329439820b7e8f8de41bca902 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 106663 - timestamp: 1702146352558 - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda sha256: 460afe7ba0882e6d2fcc0ad1568dce27025110ec09c2b9ce9e3b49d61e52ce6b md5: f95dc08366f2a452005062b5bcceac51 @@ -2396,7 +1536,6 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT - purls: [] size: 75654 timestamp: 1779279058576 - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda @@ -2406,7 +1545,6 @@ packages: - __osx >=10.13 license: MIT license_family: MIT - purls: [] size: 53583 timestamp: 1769456300951 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda @@ -2419,7 +1557,6 @@ packages: - libgcc-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 424164 timestamp: 1778271183296 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda @@ -2431,7 +1568,6 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 139925 timestamp: 1778271458366 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda @@ -2443,7 +1579,6 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 1063687 timestamp: 1778271196574 - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda @@ -2458,7 +1593,6 @@ packages: - blas 2.308 openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 19030 timestamp: 1779860046842 - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda @@ -2469,7 +1603,6 @@ packages: constrains: - xz 5.8.3.* license: 0BSD - purls: [] size: 105724 timestamp: 1775826029494 - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda @@ -2481,22 +1614,6 @@ packages: license_family: BSD size: 79899 timestamp: 1769482558610 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.68.1-h70048d4_0.conda - sha256: 899551e16aac9dfb85bfc2fd98b655f4d1b7fea45720ec04ccb93d95b4d24798 - md5: dba4c95e2fe24adcae4b77ebf33559ae - depends: - - __osx >=11.0 - - c-ares >=1.34.6,<2.0a0 - - libcxx >=19 - - libev >=4.33,<4.34.0a0 - - libev >=4.33,<5.0a0 - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.5,<4.0a0 - license: MIT - license_family: MIT - purls: [] - size: 606749 - timestamp: 1773854765508 - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda sha256: 2c2ffe7c3ab7becd47ad308946873d2bdc219625af32a53d10efbaa54b595d31 md5: 30666a6f0afe1471e999eca7ae5c8179 @@ -2509,7 +1626,6 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD - purls: [] size: 6287889 timestamp: 1776996499823 - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda @@ -2520,21 +1636,8 @@ packages: - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing - purls: [] size: 1010419 timestamp: 1780575011758 -- conda: https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.11.1-hed3591d_0.conda - sha256: 00654ba9e5f73aa1f75c1f69db34a19029e970a4aeb0fa8615934d8e9c369c3c - md5: a6cb15db1c2dc4d3a5f6cf3772e09e81 - depends: - - __osx >=10.13 - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.0,<4.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 284216 - timestamp: 1745608575796 - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda sha256: 4c6da089952b2d70150c74234679d6f7ac04f4a98f9432dec724968f912691e7 md5: 30439ff30578e504ee5e0b390afc8c65 @@ -2544,7 +1647,6 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other - purls: [] size: 59000 timestamp: 1774073052242 - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda @@ -2557,7 +1659,6 @@ packages: - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE - purls: [] size: 310879 timestamp: 1780456054580 - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda @@ -2566,7 +1667,6 @@ packages: depends: - __osx >=11.0 license: X11 AND BSD-3-Clause - purls: [] size: 831711 timestamp: 1777423052277 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda @@ -2584,8 +1684,6 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/numpy?source=hash-mapping size: 8593034 timestamp: 1779169256521 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py312h746d82c_0.conda @@ -2630,7 +1728,6 @@ packages: - ca-certificates license: Apache-2.0 license_family: Apache - purls: [] size: 2776564 timestamp: 1775589970694 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda @@ -2685,8 +1782,6 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/pandas?source=hash-mapping size: 14558446 timestamp: 1778602873120 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py312h8e27051_0.conda @@ -2816,7 +1911,6 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 - purls: [] size: 15664115 timestamp: 1772730794934 - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.13-ha9537fe_0_cpython.conda @@ -2871,7 +1965,6 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL - purls: [] size: 317819 timestamp: 1765813692798 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda @@ -2892,8 +1985,6 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/scipy?source=hash-mapping size: 15513987 timestamp: 1779875850168 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda @@ -2944,20 +2035,8 @@ packages: - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD - purls: [] size: 3282953 timestamp: 1769460532442 -- conda: https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.7-h3eecb57_6.conda - sha256: 47101a4055a70a4876ffc87b750ab2287b67eca793f21c8224be5e1ee6394d3f - md5: 727109b184d680772e3122f40136d5ca - depends: - - __osx >=10.13 - - libzlib >=1.3.1,<2.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 528148 - timestamp: 1764777156963 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda build_number: 7 sha256: 7acaa2e0782cad032bdaf756b536874346ac1375745fb250e9bdd6a48a7ab3cd @@ -2966,120 +2045,8 @@ packages: - llvm-openmp >=9.0.1 license: BSD-3-Clause license_family: BSD - purls: [] size: 8325 timestamp: 1764092507920 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-auth-0.10.3-hceed5df_2.conda - sha256: b4689664156e8067ba1aa97125f2a309a96b2bc0d1c608f4a88f30ea1f4c9aba - md5: e7501df14d3145fc86943ebfeb76a402 - depends: - - __osx >=11.0 - - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 116718 - timestamp: 1780598398659 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-cal-0.9.14-h81c6212_2.conda - sha256: 557bc47cbfd01dc569b930c102cd56ca5ba67750bd51a4fcee445246e7e536cd - md5: dcac0aa854a1f7f58a59226f5309a44e - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 45764 - timestamp: 1780567235337 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-common-0.14.0-h84a0fba_0.conda - sha256: 223f67551038366555e6934802d8b375547b142157aad3fc3654c720ac1525c0 - md5: 3a49923f2b3987a833a264caca603f84 - depends: - - __osx >=11.0 - license: Apache-2.0 - license_family: Apache - purls: [] - size: 226438 - timestamp: 1780161234587 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-compression-0.3.2-h61d3404_2.conda - sha256: 4289ff476103d109623bd413b12d61307d6267e87fc6a8c29b0aec71dfa8fd84 - md5: 497edff11fcb32865d8c5d6ab3aef6e0 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 21529 - timestamp: 1780566290492 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-http-0.11.0-h0a63974_2.conda - sha256: 06d3b08ed19cd63fd75750e325f19ebf7183b22ee27cbe2ca7b7dd6725d34885 - md5: f0fc8139091eb8245209bb9ee8911a82 - depends: - - __osx >=11.0 - - aws-c-compression >=0.3.2,<0.3.3.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 177282 - timestamp: 1780586850553 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-io-0.26.3-h58c0f83_4.conda - sha256: 18f51bdc45eabe01ca68edf5ccc73369b3201639790575e6776f3efaea6e4356 - md5: b33f51eca94f6ccbd772ca4043fe1718 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 176913 - timestamp: 1780576001260 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-s3-0.12.5-h43def2a_1.conda - sha256: 0a99b506bbe21f00f21047db50b2eea2ff8a0b1146ff0fba7d04b39a568453f4 - md5: 7dc63973f9fe772985b8c2f8ba5958ce - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-checksums >=0.2.10,<0.2.11.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-auth >=0.10.3,<0.10.4.0a0 - - aws-c-cal >=0.9.14,<0.9.15.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 132141 - timestamp: 1780609600116 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-c-sdkutils-0.2.4-h61d3404_6.conda - sha256: ef53cd1e30bc8c865c44df6f097f36361945665157e63957d68fe90aa7e4d66c - md5: 127bce41f9e6cc3bdb9e6daed95896d9 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 53659 - timestamp: 1780568618924 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/aws-checksums-0.2.10-h61d3404_2.conda - sha256: 9af1483700bb29870297e2390838d3c31293e8cf80fd8a8a9bd9a1446020a8d8 - md5: 7c5f6a6efce80e728c1f743e064ab657 - depends: - - __osx >=11.0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - license: Apache-2.0 - license_family: APACHE - purls: [] - size: 91975 - timestamp: 1780568646105 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda sha256: 540fe54be35fac0c17feefbdc3e29725cce05d7367ffedfaaa1bdda234b019df md5: 620b85a3f45526a8bc4d23fd78fc22f0 @@ -3087,19 +2054,8 @@ packages: - __osx >=11.0 license: bzip2-1.0.6 license_family: BSD - purls: [] size: 124834 timestamp: 1771350416561 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/c-ares-1.34.6-hc919400_0.conda - sha256: 2995f2aed4e53725e5efbc28199b46bf311c3cab2648fc4f10c2227d6d5fa196 - md5: bcb3cba70cf1eec964a03b4ba7775f01 - depends: - - __osx >=11.0 - license: MIT - license_family: MIT - purls: [] - size: 180327 - timestamp: 1765215064054 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda sha256: d9475f473084602003da38e373604b48b674b5fbd5939eb6f26b757cbda89f28 md5: 2e3107762a2b8bb31093fe14bab1fe17 @@ -3111,8 +2067,6 @@ packages: - tomli license: Apache-2.0 license_family: APACHE - purls: - - pkg:pypi/coverage?source=hash-mapping size: 397978 timestamp: 1779838426505 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py312h04c11ed_0.conda @@ -3141,46 +2095,6 @@ packages: license_family: APACHE size: 396380 timestamp: 1779838267496 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/h5py-3.16.0-nompi_py311hf10ccac_102.conda - sha256: 3d8437c0633c9055228db8d1fa00daceea5137075bdbce4bb0f7747466da0b09 - md5: 3921ef0b72feb738aa5f4107bb6bb084 - depends: - - __osx >=11.0 - - cached-property - - hdf5 >=2.1.0,<3.0a0 - - numpy >=1.23,<3 - - python >=3.11,<3.12.0a0 - - python >=3.11,<3.12.0a0 *_cpython - - python_abi 3.11.* *_cp311 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/h5py?source=hash-mapping - size: 1193405 - timestamp: 1775582985212 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/hdf5-2.1.0-nompi_h9bfbf6c_107.conda - sha256: 67e9ef0dfd22a37ff51d0b19aa35e9f7da21739a624976bcac1f72ab1698e8f8 - md5: fb804a23360d2b40c4f9d15a8bf0b869 - depends: - - __osx >=11.0 - - aws-c-auth >=0.10.3,<0.10.4.0a0 - - aws-c-common >=0.14.0,<0.14.1.0a0 - - aws-c-http >=0.11.0,<0.11.1.0a0 - - aws-c-io >=0.26.3,<0.26.4.0a0 - - aws-c-s3 >=0.12.5,<0.12.6.0a0 - - aws-c-sdkutils >=0.2.4,<0.2.5.0a0 - - libaec >=1.1.5,<2.0a0 - - libcurl >=8.20.0,<9.0a0 - - libcxx >=19 - - libgfortran - - libgfortran5 >=14.3.0 - - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.6,<4.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 3562608 - timestamp: 1780924273738 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda sha256: 3a7907a17e9937d3a46dfd41cffaf815abad59a569440d1e25177c15fd0684e5 md5: f1182c91c0de31a7abd40cedf6a5ebef @@ -3188,34 +2102,8 @@ packages: - __osx >=11.0 license: MIT license_family: MIT - purls: [] size: 12361647 timestamp: 1773822915649 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/krb5-1.22.2-h385eeb1_0.conda - sha256: c0a0bf028fe7f3defcdcaa464e536cf1b202d07451e18ad83fdd169d15bef6ed - md5: e446e1822f4da8e5080a9de93474184d - depends: - - __osx >=11.0 - - libcxx >=19 - - libedit >=3.1.20250104,<3.2.0a0 - - libedit >=3.1.20250104,<4.0a0 - - openssl >=3.5.5,<4.0a0 - license: MIT - license_family: MIT - purls: [] - size: 1160828 - timestamp: 1769770119811 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libaec-1.1.5-h8664d51_0.conda - sha256: af9cd8db11eb719e38a3340c88bb4882cf19b5b4237d93845224489fc2a13b46 - md5: 13e6d9ae0efbc9d2e9a01a91f4372b41 - depends: - - __osx >=11.0 - - libcxx >=19 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 30390 - timestamp: 1769222133373 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda build_number: 8 sha256: 8f5ec18ead0619a9cf0f38b49796c22f6fc0f44850c0df2baea0f5277db16e75 @@ -3231,7 +2119,6 @@ packages: - mkl <2027 license: BSD-3-Clause license_family: BSD - purls: [] size: 18949 timestamp: 1779859141315 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda @@ -3246,25 +2133,8 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 18911 timestamp: 1779859147634 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcurl-8.20.0-hd5a2499_0.conda - sha256: 38c0bc634b61e542776e97cfd15d5d41edd304d4e47c333004d2d622439b2381 - md5: 2f57b7d0c6adda88957586b7afd78438 - depends: - - __osx >=11.0 - - krb5 >=1.22.2,<1.23.0a0 - - libnghttp2 >=1.68.1,<2.0a0 - - libssh2 >=1.11.1,<2.0a0 - - libzlib >=1.3.2,<2.0a0 - - openssl >=3.5.6,<4.0a0 - - zstd >=1.5.7,<1.6.0a0 - license: curl - license_family: MIT - purls: [] - size: 400568 - timestamp: 1777462251987 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda sha256: cceb668dc1b71f054b1036dd83eca2e02c0c3a4b2ba3ad28c74a982d819597a3 md5: 0325fbe13eb6dd39234eb305ac1b3cb8 @@ -3272,29 +2142,8 @@ packages: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache - purls: [] size: 568252 timestamp: 1780441702930 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libedit-3.1.20250104-pl5321hafb1f1b_0.conda - sha256: 66aa216a403de0bb0c1340a88d1a06adaff66bae2cfd196731aa24db9859d631 - md5: 44083d2d2c2025afca315c7a172eab2b - depends: - - ncurses - - __osx >=11.0 - - ncurses >=6.5,<7.0a0 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 107691 - timestamp: 1738479560845 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libev-4.33-h93a5062_2.conda - sha256: 95cecb3902fbe0399c3a7e67a5bed1db813e5ab0e22f4023a5e0f722f2cc214f - md5: 36d33e440c31857372a72137f78bacf5 - license: BSD-2-Clause - license_family: BSD - purls: [] - size: 107458 - timestamp: 1702146414478 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda sha256: 3133fb6bfa871288b92c8b8752696686a841bf4ffe035aa3038033c9e15b738e md5: ef22e9ab1dc7c2f334252f565f90b3b8 @@ -3304,7 +2153,6 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT - purls: [] size: 69110 timestamp: 1779278728511 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda @@ -3314,7 +2162,6 @@ packages: - __osx >=11.0 license: MIT license_family: MIT - purls: [] size: 40979 timestamp: 1769456747661 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda @@ -3327,7 +2174,6 @@ packages: - libgomp 15.2.0 19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 404080 timestamp: 1778273064154 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda @@ -3339,7 +2185,6 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 139675 timestamp: 1778273280875 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda @@ -3351,7 +2196,6 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL - purls: [] size: 599691 timestamp: 1778273075448 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda @@ -3366,7 +2210,6 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD - purls: [] size: 18925 timestamp: 1779859153970 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda @@ -3377,7 +2220,6 @@ packages: constrains: - xz 5.8.3.* license: 0BSD - purls: [] size: 92472 timestamp: 1775825802659 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda @@ -3389,22 +2231,6 @@ packages: license_family: BSD size: 73690 timestamp: 1769482560514 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libnghttp2-1.68.1-h8f3e76b_0.conda - sha256: 2bc7bc3978066f2c274ebcbf711850cc9ab92e023e433b9631958a098d11e10a - md5: 6ea18834adbc3b33df9bd9fb45eaf95b - depends: - - __osx >=11.0 - - c-ares >=1.34.6,<2.0a0 - - libcxx >=19 - - libev >=4.33,<4.34.0a0 - - libev >=4.33,<5.0a0 - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.5,<4.0a0 - license: MIT - license_family: MIT - purls: [] - size: 576526 - timestamp: 1773854624224 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda sha256: 9dd455b2d172aeedfa2058d324b5b5822b0bc1b7c1f32cd183d7078540d2f6eb md5: 909e41855c29f0d52ae630198cd57135 @@ -3417,7 +2243,6 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD - purls: [] size: 4304965 timestamp: 1776995497368 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda @@ -3428,20 +2253,8 @@ packages: - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing - purls: [] size: 927724 timestamp: 1780575223548 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/libssh2-1.11.1-h1590b86_0.conda - sha256: 8bfe837221390ffc6f111ecca24fa12d4a6325da0c8d131333d63d6c37f27e0a - md5: b68e8f66b94b44aaa8de4583d3d4cc40 - depends: - - libzlib >=1.3.1,<2.0a0 - - openssl >=3.5.0,<4.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 279193 - timestamp: 1745608793272 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda sha256: 361415a698514b19a852f5d1123c5da746d4642139904156ddfca7c922d23a05 md5: bc5a5721b6439f2f62a84f2548136082 @@ -3451,7 +2264,6 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other - purls: [] size: 47759 timestamp: 1774072956767 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda @@ -3464,7 +2276,6 @@ packages: - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE - purls: [] size: 285162 timestamp: 1780455637760 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda @@ -3473,7 +2284,6 @@ packages: depends: - __osx >=11.0 license: X11 AND BSD-3-Clause - purls: [] size: 805509 timestamp: 1777423252320 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda @@ -3491,8 +2301,6 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/numpy?source=hash-mapping size: 7456206 timestamp: 1779169211856 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda @@ -3537,7 +2345,6 @@ packages: - ca-certificates license: Apache-2.0 license_family: Apache - purls: [] size: 3106008 timestamp: 1775587972483 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda @@ -3593,8 +2400,6 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/pandas?source=hash-mapping size: 14329411 timestamp: 1778602822615 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py312h6510ced_0.conda @@ -3726,7 +2531,6 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 - purls: [] size: 14753109 timestamp: 1772730203101 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.13-h8561d8f_0_cpython.conda @@ -3781,7 +2585,6 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL - purls: [] size: 313930 timestamp: 1765813902568 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda @@ -3802,8 +2605,6 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD - purls: - - pkg:pypi/scipy?source=compressed-mapping size: 13954661 timestamp: 1779874558902 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda @@ -3854,20 +2655,5 @@ packages: - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD - purls: [] size: 3127137 timestamp: 1769460817696 -- conda: https://conda.anaconda.org/conda-forge/osx-arm64/zstd-1.5.7-hbf9d68e_6.conda - sha256: 9485ba49e8f47d2b597dd399e88f4802e100851b27c21d7525625b0b4025a5d9 - md5: ab136e4c34e97f34fb621d2592a393d8 - depends: - - __osx >=11.0 - - libzlib >=1.3.1,<2.0a0 - license: BSD-3-Clause - license_family: BSD - purls: [] - size: 433413 - timestamp: 1764777166076 -- pypi: git+https://github.com/pennmem/cmlreaders#a6f34080d2da4d24db85e004dafde2148cb135fd - name: cmlreaders - version: 0.12.2 diff --git a/pixi.toml b/pixi.toml index 1012b9c..6ebb640 100644 --- a/pixi.toml +++ b/pixi.toml @@ -21,27 +21,11 @@ python = "3.12.*" [feature.py313.dependencies] python = "3.13.*" -# Real-data integration env: cmlreaders to read ltpFR2 behavioral events off -# rhino. Only usable on a host with the /protocols/ltp mount; the real-data -# tests skip cleanly elsewhere. cmlreaders is not on PyPI, so install from git. -[feature.rhino.dependencies] -python = "3.11.*" -h5py = "*" -setuptools = "*" -pip = "*" -[feature.rhino.pypi-dependencies] -cmlreaders = { git = "https://github.com/pennmem/cmlreaders.git" } -# cmlreaders' setup.py imports pandas at build time; build against the env's -# already-installed conda numpy/pandas rather than an isolated build env. -[feature.rhino.pypi-options] -no-build-isolation = ["cmlreaders"] - [environments] default = ["test"] py311 = ["py311", "test"] py312 = ["py312", "test"] py313 = ["py313", "test"] -rhino = ["rhino", "test"] [tasks] # Pure-Python package: no compiled extensions to build. This task is the diff --git a/pytest.ini b/pytest.ini index 43b675b..304f129 100644 --- a/pytest.ini +++ b/pytest.ini @@ -8,4 +8,3 @@ markers = regression: golden-master behavior lock integration: end-to-end pipeline on synthetic or real data pins_bug: pins CURRENT (known-buggy) behavior; see bug_report.md - needs_data: requires rhino mount + cmlreaders (real ltpFR2 data); skipped otherwise diff --git a/tests/data/_regenerate_ltpfr2.py b/tests/data/_regenerate_ltpfr2.py new file mode 100644 index 0000000..56997b1 --- /dev/null +++ b/tests/data/_regenerate_ltpfr2.py @@ -0,0 +1,61 @@ +"""Regenerate the committed ltpFR2 real-data fixture + comprehensive golden. + +One-time/maintenance script. Requires cmlreaders + the rhino /protocols/ltp mount. +Writes: + tests/data/ltpfr2_5sessions.csv - 5 sessions of LTP093 (WORD + REC_WORD events) + tests/data/ltpfr2_golden.npz - frozen pybeh_pd outputs on that data + +The golden freezes every analysis that applies to plain free-recall events (no +external semantic space): the matrix builders, the lag-CRP family (incl. the +repeated-presentation variants), and the temporal clustering factor, both +pooled-over-sessions and per-session. Semantic CRP / distance-factor are NOT +included here because ltpFR2 events carry no semantic feature columns; those are +locked on the synthetic suite (tests/regression) where features exist. + +The integration test reads these committed files and needs neither cmlreaders nor +rhino. Re-run only to refresh the fixture (an intentional, reviewed change). +""" +import os +import sys + +import numpy as np +import pandas as pd +import cmlreaders as cml + +HERE = os.path.dirname(__file__) +sys.path.insert(0, os.path.join(HERE, "..", "..")) # repo root (pybeh_pd) +sys.path.insert(0, os.path.join(HERE, "..")) # tests/ (real_data) +from real_data import capture_outputs # noqa: E402 + +SUBJECT, N_SESSIONS, ITEMNO = "LTP093", 5, "item_num" + + +def load(): + idx = cml.get_data_index("ltp", rootdir="/").query("experiment == 'ltpFR2'") + rows = (idx.query("subject == @SUBJECT and session != 23") + .sort_values("session").head(N_SESSIONS)) + keep = ["subject", "session", "list", "type", "item_num", "serialpos"] + frames = [] + for r in rows.itertuples(): + ev = cml.CMLReader(subject=r.subject, session=int(r.session), + experiment="ltpFR2", rootdir="/").load("events") + if "list" in ev.columns: + ev = ev.drop(columns="list") + ev = ev.rename(columns={"trial": "list"}).query("type in ['WORD','REC_WORD']") + frames.append(ev[keep]) + return pd.concat(frames, ignore_index=True) + + +def main(): + df = load() + df.to_csv(os.path.join(HERE, "ltpfr2_5sessions.csv"), index=False) + golden = capture_outputs(df) + np.savez(os.path.join(HERE, "ltpfr2_golden.npz"), **golden) + print(f"wrote ltpfr2_5sessions.csv rows={len(df)}") + print(f"golden: {len(golden)} arrays") + for k in sorted(golden): + print(f" {k:28s} shape={golden[k].shape}") + + +if __name__ == "__main__": + main() diff --git a/tests/data/ltpfr2_5sessions.csv b/tests/data/ltpfr2_5sessions.csv new file mode 100644 index 0000000..dca953a --- /dev/null +++ b/tests/data/ltpfr2_5sessions.csv @@ -0,0 +1,4250 @@ +subject,session,list,type,item_num,serialpos +LTP093,0,1,WORD,75,1 +LTP093,0,1,WORD,857,2 +LTP093,0,1,WORD,584,3 +LTP093,0,1,WORD,442,4 +LTP093,0,1,WORD,142,5 +LTP093,0,1,WORD,1493,6 +LTP093,0,1,WORD,1243,7 +LTP093,0,1,WORD,1635,8 +LTP093,0,1,WORD,1006,9 +LTP093,0,1,WORD,782,10 +LTP093,0,1,WORD,1219,11 +LTP093,0,1,WORD,499,12 +LTP093,0,1,WORD,935,13 +LTP093,0,1,WORD,1229,14 +LTP093,0,1,WORD,1047,15 +LTP093,0,1,WORD,696,16 +LTP093,0,1,WORD,658,17 +LTP093,0,1,WORD,267,18 +LTP093,0,1,WORD,1295,19 +LTP093,0,1,WORD,226,20 +LTP093,0,1,WORD,1461,21 +LTP093,0,1,WORD,94,22 +LTP093,0,1,WORD,734,23 +LTP093,0,1,WORD,876,24 +LTP093,0,1,REC_WORD,75,1 +LTP093,0,1,REC_WORD,857,2 +LTP093,0,1,REC_WORD,584,3 +LTP093,0,1,REC_WORD,442,4 +LTP093,0,1,REC_WORD,142,5 +LTP093,0,1,REC_WORD,1493,6 +LTP093,0,1,REC_WORD,1243,7 +LTP093,0,1,REC_WORD,734,23 +LTP093,0,1,REC_WORD,226,20 +LTP093,0,1,REC_WORD,935,13 +LTP093,0,1,REC_WORD,1229,14 +LTP093,0,1,REC_WORD,1047,15 +LTP093,0,1,REC_WORD,696,16 +LTP093,0,1,REC_WORD,1295,19 +LTP093,0,1,REC_WORD,1006,9 +LTP093,0,1,REC_WORD,782,10 +LTP093,0,1,REC_WORD,94,22 +LTP093,0,1,REC_WORD,734,23 +LTP093,0,2,WORD,494,1 +LTP093,0,2,WORD,1374,2 +LTP093,0,2,WORD,169,3 +LTP093,0,2,WORD,1032,4 +LTP093,0,2,WORD,997,5 +LTP093,0,2,WORD,1246,6 +LTP093,0,2,WORD,592,7 +LTP093,0,2,WORD,1606,8 +LTP093,0,2,WORD,1609,9 +LTP093,0,2,WORD,1358,10 +LTP093,0,2,WORD,1113,11 +LTP093,0,2,WORD,1545,12 +LTP093,0,2,WORD,749,13 +LTP093,0,2,WORD,1119,14 +LTP093,0,2,WORD,1057,15 +LTP093,0,2,WORD,697,16 +LTP093,0,2,WORD,573,17 +LTP093,0,2,WORD,1158,18 +LTP093,0,2,WORD,1521,19 +LTP093,0,2,WORD,1526,20 +LTP093,0,2,WORD,388,21 +LTP093,0,2,WORD,599,22 +LTP093,0,2,WORD,134,23 +LTP093,0,2,WORD,177,24 +LTP093,0,2,REC_WORD,388,21 +LTP093,0,2,REC_WORD,599,22 +LTP093,0,2,REC_WORD,134,23 +LTP093,0,2,REC_WORD,177,24 +LTP093,0,2,REC_WORD,494,1 +LTP093,0,2,REC_WORD,1374,2 +LTP093,0,2,REC_WORD,169,3 +LTP093,0,2,REC_WORD,1032,4 +LTP093,0,2,REC_WORD,1609,9 +LTP093,0,2,REC_WORD,1358,10 +LTP093,0,2,REC_WORD,997,5 +LTP093,0,2,REC_WORD,1246,6 +LTP093,0,2,REC_WORD,749,13 +LTP093,0,2,REC_WORD,1119,14 +LTP093,0,2,REC_WORD,573,17 +LTP093,0,2,REC_WORD,1158,18 +LTP093,0,2,REC_WORD,1521,19 +LTP093,0,3,WORD,988,1 +LTP093,0,3,WORD,1611,2 +LTP093,0,3,WORD,989,3 +LTP093,0,3,WORD,635,4 +LTP093,0,3,WORD,159,5 +LTP093,0,3,WORD,437,6 +LTP093,0,3,WORD,1580,7 +LTP093,0,3,WORD,488,8 +LTP093,0,3,WORD,38,9 +LTP093,0,3,WORD,872,10 +LTP093,0,3,WORD,108,11 +LTP093,0,3,WORD,895,12 +LTP093,0,3,WORD,682,13 +LTP093,0,3,WORD,827,14 +LTP093,0,3,WORD,839,15 +LTP093,0,3,WORD,390,16 +LTP093,0,3,WORD,953,17 +LTP093,0,3,WORD,879,18 +LTP093,0,3,WORD,618,19 +LTP093,0,3,WORD,994,20 +LTP093,0,3,WORD,1242,21 +LTP093,0,3,WORD,1349,22 +LTP093,0,3,WORD,683,23 +LTP093,0,3,WORD,852,24 +LTP093,0,3,REC_WORD,994,20 +LTP093,0,3,REC_WORD,1349,22 +LTP093,0,3,REC_WORD,618,19 +LTP093,0,3,REC_WORD,879,18 +LTP093,0,3,REC_WORD,953,17 +LTP093,0,3,REC_WORD,635,4 +LTP093,0,3,REC_WORD,159,5 +LTP093,0,3,REC_WORD,988,1 +LTP093,0,3,REC_WORD,1611,2 +LTP093,0,3,REC_WORD,989,3 +LTP093,0,3,REC_WORD,437,6 +LTP093,0,3,REC_WORD,1580,7 +LTP093,0,3,REC_WORD,390,16 +LTP093,0,4,WORD,530,1 +LTP093,0,4,WORD,793,2 +LTP093,0,4,WORD,1411,3 +LTP093,0,4,WORD,431,4 +LTP093,0,4,WORD,1405,5 +LTP093,0,4,WORD,800,6 +LTP093,0,4,WORD,1636,7 +LTP093,0,4,WORD,1287,8 +LTP093,0,4,WORD,1199,9 +LTP093,0,4,WORD,1221,10 +LTP093,0,4,WORD,1066,11 +LTP093,0,4,WORD,1332,12 +LTP093,0,4,WORD,1021,13 +LTP093,0,4,WORD,848,14 +LTP093,0,4,WORD,719,15 +LTP093,0,4,WORD,316,16 +LTP093,0,4,WORD,1527,17 +LTP093,0,4,WORD,778,18 +LTP093,0,4,WORD,1108,19 +LTP093,0,4,WORD,833,20 +LTP093,0,4,WORD,386,21 +LTP093,0,4,WORD,446,22 +LTP093,0,4,WORD,763,23 +LTP093,0,4,WORD,1155,24 +LTP093,0,4,REC_WORD,763,23 +LTP093,0,5,WORD,707,1 +LTP093,0,5,WORD,1194,2 +LTP093,0,5,WORD,172,3 +LTP093,0,5,WORD,339,4 +LTP093,0,5,WORD,29,5 +LTP093,0,5,WORD,1070,6 +LTP093,0,5,WORD,13,7 +LTP093,0,5,WORD,338,8 +LTP093,0,5,WORD,439,9 +LTP093,0,5,WORD,1011,10 +LTP093,0,5,WORD,888,11 +LTP093,0,5,WORD,1414,12 +LTP093,0,5,WORD,248,13 +LTP093,0,5,WORD,1326,14 +LTP093,0,5,WORD,866,15 +LTP093,0,5,WORD,689,16 +LTP093,0,5,WORD,1395,17 +LTP093,0,5,WORD,959,18 +LTP093,0,5,WORD,1256,19 +LTP093,0,5,WORD,211,20 +LTP093,0,5,WORD,1587,21 +LTP093,0,5,WORD,1124,22 +LTP093,0,5,WORD,1282,23 +LTP093,0,5,WORD,295,24 +LTP093,0,5,REC_WORD,1124,22 +LTP093,0,5,REC_WORD,707,1 +LTP093,0,5,REC_WORD,1194,2 +LTP093,0,5,REC_WORD,172,3 +LTP093,0,5,REC_WORD,339,4 +LTP093,0,5,REC_WORD,1395,17 +LTP093,0,5,REC_WORD,959,18 +LTP093,0,5,REC_WORD,1256,19 +LTP093,0,6,WORD,348,1 +LTP093,0,6,WORD,1544,2 +LTP093,0,6,WORD,136,3 +LTP093,0,6,WORD,327,4 +LTP093,0,6,WORD,798,5 +LTP093,0,6,WORD,575,6 +LTP093,0,6,WORD,1388,7 +LTP093,0,6,WORD,812,8 +LTP093,0,6,WORD,12,9 +LTP093,0,6,WORD,1472,10 +LTP093,0,6,WORD,495,11 +LTP093,0,6,WORD,755,12 +LTP093,0,6,WORD,1087,13 +LTP093,0,6,WORD,341,14 +LTP093,0,6,WORD,1183,15 +LTP093,0,6,WORD,383,16 +LTP093,0,6,WORD,1633,17 +LTP093,0,6,WORD,996,18 +LTP093,0,6,WORD,340,19 +LTP093,0,6,WORD,1392,20 +LTP093,0,6,WORD,667,21 +LTP093,0,6,WORD,88,22 +LTP093,0,6,WORD,1245,23 +LTP093,0,6,WORD,1329,24 +LTP093,0,6,REC_WORD,755,12 +LTP093,0,6,REC_WORD,495,11 +LTP093,0,6,REC_WORD,1183,15 +LTP093,0,6,REC_WORD,383,16 +LTP093,0,6,REC_WORD,1633,17 +LTP093,0,6,REC_WORD,340,19 +LTP093,0,6,REC_WORD,12,9 +LTP093,0,6,REC_WORD,1472,10 +LTP093,0,6,REC_WORD,327,4 +LTP093,0,6,REC_WORD,136,3 +LTP093,0,6,REC_WORD,996,18 +LTP093,0,7,WORD,1562,1 +LTP093,0,7,WORD,184,2 +LTP093,0,7,WORD,492,3 +LTP093,0,7,WORD,466,4 +LTP093,0,7,WORD,1080,5 +LTP093,0,7,WORD,1292,6 +LTP093,0,7,WORD,1505,7 +LTP093,0,7,WORD,1486,8 +LTP093,0,7,WORD,1625,9 +LTP093,0,7,WORD,1089,10 +LTP093,0,7,WORD,1456,11 +LTP093,0,7,WORD,732,12 +LTP093,0,7,WORD,901,13 +LTP093,0,7,WORD,861,14 +LTP093,0,7,WORD,1622,15 +LTP093,0,7,WORD,796,16 +LTP093,0,7,WORD,372,17 +LTP093,0,7,WORD,661,18 +LTP093,0,7,WORD,746,19 +LTP093,0,7,WORD,1496,20 +LTP093,0,7,WORD,733,21 +LTP093,0,7,WORD,1002,22 +LTP093,0,7,WORD,358,23 +LTP093,0,7,WORD,627,24 +LTP093,0,7,REC_WORD,1562,1 +LTP093,0,7,REC_WORD,184,2 +LTP093,0,7,REC_WORD,1002,22 +LTP093,0,7,REC_WORD,492,3 +LTP093,0,7,REC_WORD,466,4 +LTP093,0,7,REC_WORD,1486,8 +LTP093,0,7,REC_WORD,1625,9 +LTP093,0,7,REC_WORD,1089,10 +LTP093,0,7,REC_WORD,1456,11 +LTP093,0,7,REC_WORD,1080,5 +LTP093,0,7,REC_WORD,1292,6 +LTP093,0,7,REC_WORD,1544,2 +LTP093,0,8,WORD,131,1 +LTP093,0,8,WORD,484,2 +LTP093,0,8,WORD,429,3 +LTP093,0,8,WORD,61,4 +LTP093,0,8,WORD,1515,5 +LTP093,0,8,WORD,847,6 +LTP093,0,8,WORD,598,7 +LTP093,0,8,WORD,1385,8 +LTP093,0,8,WORD,415,9 +LTP093,0,8,WORD,1125,10 +LTP093,0,8,WORD,561,11 +LTP093,0,8,WORD,645,12 +LTP093,0,8,WORD,278,13 +LTP093,0,8,WORD,1403,14 +LTP093,0,8,WORD,1382,15 +LTP093,0,8,WORD,578,16 +LTP093,0,8,WORD,821,17 +LTP093,0,8,WORD,435,18 +LTP093,0,8,WORD,692,19 +LTP093,0,8,WORD,1536,20 +LTP093,0,8,WORD,395,21 +LTP093,0,8,WORD,714,22 +LTP093,0,8,WORD,1448,23 +LTP093,0,8,WORD,654,24 +LTP093,0,8,REC_WORD,692,19 +LTP093,0,8,REC_WORD,1536,20 +LTP093,0,8,REC_WORD,415,9 +LTP093,0,8,REC_WORD,1125,10 +LTP093,0,8,REC_WORD,561,11 +LTP093,0,8,REC_WORD,645,12 +LTP093,0,8,REC_WORD,429,3 +LTP093,0,9,WORD,179,1 +LTP093,0,9,WORD,999,2 +LTP093,0,9,WORD,417,3 +LTP093,0,9,WORD,809,4 +LTP093,0,9,WORD,579,5 +LTP093,0,9,WORD,541,6 +LTP093,0,9,WORD,1488,7 +LTP093,0,9,WORD,397,8 +LTP093,0,9,WORD,604,9 +LTP093,0,9,WORD,724,10 +LTP093,0,9,WORD,593,11 +LTP093,0,9,WORD,1280,12 +LTP093,0,9,WORD,343,13 +LTP093,0,9,WORD,737,14 +LTP093,0,9,WORD,299,15 +LTP093,0,9,WORD,1631,16 +LTP093,0,9,WORD,1294,17 +LTP093,0,9,WORD,829,18 +LTP093,0,9,WORD,258,19 +LTP093,0,9,WORD,1238,20 +LTP093,0,9,WORD,559,21 +LTP093,0,9,WORD,1533,22 +LTP093,0,9,WORD,1017,23 +LTP093,0,9,WORD,168,24 +LTP093,0,9,REC_WORD,179,1 +LTP093,0,9,REC_WORD,999,2 +LTP093,0,9,REC_WORD,417,3 +LTP093,0,9,REC_WORD,397,8 +LTP093,0,9,REC_WORD,604,9 +LTP093,0,9,REC_WORD,724,10 +LTP093,0,9,REC_WORD,593,11 +LTP093,0,9,REC_WORD,1488,7 +LTP093,0,9,REC_WORD,541,6 +LTP093,0,9,REC_WORD,1294,17 +LTP093,0,9,REC_WORD,829,18 +LTP093,0,9,REC_WORD,343,13 +LTP093,0,9,REC_WORD,1280,12 +LTP093,0,9,REC_WORD,1017,23 +LTP093,0,9,REC_WORD,559,21 +LTP093,0,10,WORD,908,1 +LTP093,0,10,WORD,183,2 +LTP093,0,10,WORD,546,3 +LTP093,0,10,WORD,1557,4 +LTP093,0,10,WORD,600,5 +LTP093,0,10,WORD,1581,6 +LTP093,0,10,WORD,602,7 +LTP093,0,10,WORD,520,8 +LTP093,0,10,WORD,24,9 +LTP093,0,10,WORD,1628,10 +LTP093,0,10,WORD,1451,11 +LTP093,0,10,WORD,328,12 +LTP093,0,10,WORD,1530,13 +LTP093,0,10,WORD,1200,14 +LTP093,0,10,WORD,922,15 +LTP093,0,10,WORD,1546,16 +LTP093,0,10,WORD,591,17 +LTP093,0,10,WORD,576,18 +LTP093,0,10,WORD,1227,19 +LTP093,0,10,WORD,1071,20 +LTP093,0,10,WORD,834,21 +LTP093,0,10,WORD,1351,22 +LTP093,0,10,WORD,496,23 +LTP093,0,10,WORD,401,24 +LTP093,0,10,REC_WORD,401,24 +LTP093,0,10,REC_WORD,1530,13 +LTP093,0,10,REC_WORD,1200,14 +LTP093,0,10,REC_WORD,908,1 +LTP093,0,10,REC_WORD,183,2 +LTP093,0,10,REC_WORD,546,3 +LTP093,0,10,REC_WORD,520,8 +LTP093,0,10,REC_WORD,602,7 +LTP093,0,10,REC_WORD,24,9 +LTP093,0,11,WORD,1331,1 +LTP093,0,11,WORD,1618,2 +LTP093,0,11,WORD,1022,3 +LTP093,0,11,WORD,1592,4 +LTP093,0,11,WORD,1605,5 +LTP093,0,11,WORD,1512,6 +LTP093,0,11,WORD,1415,7 +LTP093,0,11,WORD,1250,8 +LTP093,0,11,WORD,39,9 +LTP093,0,11,WORD,1535,10 +LTP093,0,11,WORD,1343,11 +LTP093,0,11,WORD,315,12 +LTP093,0,11,WORD,1519,13 +LTP093,0,11,WORD,1284,14 +LTP093,0,11,WORD,1440,15 +LTP093,0,11,WORD,932,16 +LTP093,0,11,WORD,164,17 +LTP093,0,11,WORD,373,18 +LTP093,0,11,WORD,100,19 +LTP093,0,11,WORD,255,20 +LTP093,0,11,WORD,1608,21 +LTP093,0,11,WORD,1149,22 +LTP093,0,11,WORD,162,23 +LTP093,0,11,WORD,543,24 +LTP093,0,11,REC_WORD,162,23 +LTP093,0,11,REC_WORD,1415,7 +LTP093,0,11,REC_WORD,1618,2 +LTP093,0,11,REC_WORD,1149,22 +LTP093,0,11,REC_WORD,1608,21 +LTP093,0,11,REC_WORD,255,20 +LTP093,0,11,REC_WORD,1519,13 +LTP093,0,11,REC_WORD,1022,3 +LTP093,0,11,REC_WORD,1592,4 +LTP093,0,12,WORD,1508,1 +LTP093,0,12,WORD,790,2 +LTP093,0,12,WORD,410,3 +LTP093,0,12,WORD,1104,4 +LTP093,0,12,WORD,360,5 +LTP093,0,12,WORD,235,6 +LTP093,0,12,WORD,726,7 +LTP093,0,12,WORD,325,8 +LTP093,0,12,WORD,723,9 +LTP093,0,12,WORD,871,10 +LTP093,0,12,WORD,307,11 +LTP093,0,12,WORD,1016,12 +LTP093,0,12,WORD,1123,13 +LTP093,0,12,WORD,1060,14 +LTP093,0,12,WORD,1400,15 +LTP093,0,12,WORD,5,16 +LTP093,0,12,WORD,413,17 +LTP093,0,12,WORD,1111,18 +LTP093,0,12,WORD,1315,19 +LTP093,0,12,WORD,1159,20 +LTP093,0,12,WORD,145,21 +LTP093,0,12,WORD,86,22 +LTP093,0,12,WORD,760,23 +LTP093,0,12,WORD,565,24 +LTP093,0,12,REC_WORD,86,22 +LTP093,0,12,REC_WORD,145,21 +LTP093,0,12,REC_WORD,726,7 +LTP093,0,12,REC_WORD,1123,13 +LTP093,0,12,REC_WORD,360,5 +LTP093,0,12,REC_WORD,1104,4 +LTP093,0,12,REC_WORD,235,6 +LTP093,0,12,REC_WORD,790,2 +LTP093,0,12,REC_WORD,410,3 +LTP093,0,12,REC_WORD,1508,1 +LTP093,0,13,WORD,670,1 +LTP093,0,13,WORD,1176,2 +LTP093,0,13,WORD,198,3 +LTP093,0,13,WORD,66,4 +LTP093,0,13,WORD,1468,5 +LTP093,0,13,WORD,508,6 +LTP093,0,13,WORD,292,7 +LTP093,0,13,WORD,82,8 +LTP093,0,13,WORD,980,9 +LTP093,0,13,WORD,874,10 +LTP093,0,13,WORD,133,11 +LTP093,0,13,WORD,1076,12 +LTP093,0,13,WORD,441,13 +LTP093,0,13,WORD,1422,14 +LTP093,0,13,WORD,200,15 +LTP093,0,13,WORD,974,16 +LTP093,0,13,WORD,1408,17 +LTP093,0,13,WORD,666,18 +LTP093,0,13,WORD,1426,19 +LTP093,0,13,WORD,143,20 +LTP093,0,13,WORD,754,21 +LTP093,0,13,WORD,84,22 +LTP093,0,13,WORD,10,23 +LTP093,0,13,WORD,1031,24 +LTP093,0,13,REC_WORD,198,3 +LTP093,0,13,REC_WORD,66,4 +LTP093,0,13,REC_WORD,754,21 +LTP093,0,13,REC_WORD,670,1 +LTP093,0,13,REC_WORD,1176,2 +LTP093,0,13,REC_WORD,1031,24 +LTP093,0,14,WORD,1301,1 +LTP093,0,14,WORD,368,2 +LTP093,0,14,WORD,1171,3 +LTP093,0,14,WORD,119,4 +LTP093,0,14,WORD,1384,5 +LTP093,0,14,WORD,483,6 +LTP093,0,14,WORD,1478,7 +LTP093,0,14,WORD,408,8 +LTP093,0,14,WORD,940,9 +LTP093,0,14,WORD,1147,10 +LTP093,0,14,WORD,280,11 +LTP093,0,14,WORD,1224,12 +LTP093,0,14,WORD,870,13 +LTP093,0,14,WORD,919,14 +LTP093,0,14,WORD,580,15 +LTP093,0,14,WORD,1209,16 +LTP093,0,14,WORD,216,17 +LTP093,0,14,WORD,1341,18 +LTP093,0,14,WORD,858,19 +LTP093,0,14,WORD,1262,20 +LTP093,0,14,WORD,1140,21 +LTP093,0,14,WORD,728,22 +LTP093,0,14,WORD,1420,23 +LTP093,0,14,WORD,1327,24 +LTP093,0,14,REC_WORD,1420,23 +LTP093,0,14,REC_WORD,1327,24 +LTP093,0,14,REC_WORD,870,13 +LTP093,0,14,REC_WORD,919,14 +LTP093,0,14,REC_WORD,1147,10 +LTP093,0,14,REC_WORD,940,9 +LTP093,0,14,REC_WORD,1171,3 +LTP093,0,14,REC_WORD,119,4 +LTP093,0,14,REC_WORD,1384,5 +LTP093,0,14,REC_WORD,483,6 +LTP093,0,15,WORD,1345,1 +LTP093,0,15,WORD,641,2 +LTP093,0,15,WORD,1620,3 +LTP093,0,15,WORD,512,4 +LTP093,0,15,WORD,1036,5 +LTP093,0,15,WORD,1333,6 +LTP093,0,15,WORD,1092,7 +LTP093,0,15,WORD,553,8 +LTP093,0,15,WORD,254,9 +LTP093,0,15,WORD,353,10 +LTP093,0,15,WORD,1319,11 +LTP093,0,15,WORD,792,12 +LTP093,0,15,WORD,304,13 +LTP093,0,15,WORD,1075,14 +LTP093,0,15,WORD,715,15 +LTP093,0,15,WORD,642,16 +LTP093,0,15,WORD,567,17 +LTP093,0,15,WORD,570,18 +LTP093,0,15,WORD,794,19 +LTP093,0,15,WORD,987,20 +LTP093,0,15,WORD,447,21 +LTP093,0,15,WORD,497,22 +LTP093,0,15,WORD,1532,23 +LTP093,0,15,WORD,1192,24 +LTP093,0,15,REC_WORD,497,22 +LTP093,0,15,REC_WORD,1192,24 +LTP093,0,15,REC_WORD,1532,23 +LTP093,0,15,REC_WORD,641,2 +LTP093,0,15,REC_WORD,1345,1 +LTP093,0,15,REC_WORD,1620,3 +LTP093,0,15,REC_WORD,512,4 +LTP093,0,16,WORD,203,1 +LTP093,0,16,WORD,389,2 +LTP093,0,16,WORD,1299,3 +LTP093,0,16,WORD,731,4 +LTP093,0,16,WORD,972,5 +LTP093,0,16,WORD,1328,6 +LTP093,0,16,WORD,498,7 +LTP093,0,16,WORD,1251,8 +LTP093,0,16,WORD,785,9 +LTP093,0,16,WORD,660,10 +LTP093,0,16,WORD,801,11 +LTP093,0,16,WORD,1260,12 +LTP093,0,16,WORD,995,13 +LTP093,0,16,WORD,1272,14 +LTP093,0,16,WORD,35,15 +LTP093,0,16,WORD,166,16 +LTP093,0,16,WORD,485,17 +LTP093,0,16,WORD,1522,18 +LTP093,0,16,WORD,1330,19 +LTP093,0,16,WORD,776,20 +LTP093,0,16,WORD,771,21 +LTP093,0,16,WORD,708,22 +LTP093,0,16,WORD,1086,23 +LTP093,0,16,WORD,977,24 +LTP093,0,16,REC_WORD,203,1 +LTP093,0,16,REC_WORD,389,2 +LTP093,0,16,REC_WORD,731,4 +LTP093,0,16,REC_WORD,1299,3 +LTP093,0,16,REC_WORD,776,20 +LTP093,0,16,REC_WORD,977,24 +LTP093,0,16,REC_WORD,485,17 +LTP093,0,16,REC_WORD,995,13 +LTP093,0,16,REC_WORD,1272,14 +LTP093,0,16,REC_WORD,35,15 +LTP093,0,17,WORD,764,1 +LTP093,0,17,WORD,1144,2 +LTP093,0,17,WORD,1000,3 +LTP093,0,17,WORD,1520,4 +LTP093,0,17,WORD,104,5 +LTP093,0,17,WORD,1621,6 +LTP093,0,17,WORD,1275,7 +LTP093,0,17,WORD,675,8 +LTP093,0,17,WORD,1035,9 +LTP093,0,17,WORD,405,10 +LTP093,0,17,WORD,68,11 +LTP093,0,17,WORD,1065,12 +LTP093,0,17,WORD,283,13 +LTP093,0,17,WORD,1565,14 +LTP093,0,17,WORD,912,15 +LTP093,0,17,WORD,261,16 +LTP093,0,17,WORD,55,17 +LTP093,0,17,WORD,1132,18 +LTP093,0,17,WORD,188,19 +LTP093,0,17,WORD,633,20 +LTP093,0,17,WORD,425,21 +LTP093,0,17,WORD,937,22 +LTP093,0,17,WORD,590,23 +LTP093,0,17,WORD,885,24 +LTP093,0,17,REC_WORD,188,19 +LTP093,0,17,REC_WORD,633,20 +LTP093,0,17,REC_WORD,55,17 +LTP093,0,17,REC_WORD,1132,18 +LTP093,0,17,REC_WORD,590,23 +LTP093,0,17,REC_WORD,885,24 +LTP093,0,17,REC_WORD,283,13 +LTP093,0,17,REC_WORD,1565,14 +LTP093,0,17,REC_WORD,1065,12 +LTP093,0,17,REC_WORD,68,11 +LTP093,0,18,WORD,1303,1 +LTP093,0,18,WORD,699,2 +LTP093,0,18,WORD,1355,3 +LTP093,0,18,WORD,91,4 +LTP093,0,18,WORD,139,5 +LTP093,0,18,WORD,1061,6 +LTP093,0,18,WORD,1093,7 +LTP093,0,18,WORD,1088,8 +LTP093,0,18,WORD,840,9 +LTP093,0,18,WORD,960,10 +LTP093,0,18,WORD,659,11 +LTP093,0,18,WORD,1015,12 +LTP093,0,18,WORD,1261,13 +LTP093,0,18,WORD,240,14 +LTP093,0,18,WORD,1095,15 +LTP093,0,18,WORD,622,16 +LTP093,0,18,WORD,1370,17 +LTP093,0,18,WORD,738,18 +LTP093,0,18,WORD,1172,19 +LTP093,0,18,WORD,392,20 +LTP093,0,18,WORD,519,21 +LTP093,0,18,WORD,1369,22 +LTP093,0,18,WORD,1578,23 +LTP093,0,18,WORD,509,24 +LTP093,0,18,REC_WORD,1369,22 +LTP093,0,18,REC_WORD,1578,23 +LTP093,0,18,REC_WORD,519,21 +LTP093,0,18,REC_WORD,392,20 +LTP093,0,18,REC_WORD,1303,1 +LTP093,0,18,REC_WORD,699,2 +LTP093,0,19,WORD,378,1 +LTP093,0,19,WORD,624,2 +LTP093,0,19,WORD,199,3 +LTP093,0,19,WORD,187,4 +LTP093,0,19,WORD,601,5 +LTP093,0,19,WORD,843,6 +LTP093,0,19,WORD,1096,7 +LTP093,0,19,WORD,1438,8 +LTP093,0,19,WORD,1593,9 +LTP093,0,19,WORD,336,10 +LTP093,0,19,WORD,109,11 +LTP093,0,19,WORD,761,12 +LTP093,0,19,WORD,1503,13 +LTP093,0,19,WORD,127,14 +LTP093,0,19,WORD,916,15 +LTP093,0,19,WORD,585,16 +LTP093,0,19,WORD,893,17 +LTP093,0,19,WORD,210,18 +LTP093,0,19,WORD,175,19 +LTP093,0,19,WORD,929,20 +LTP093,0,19,WORD,230,21 +LTP093,0,19,WORD,1511,22 +LTP093,0,19,WORD,869,23 +LTP093,0,19,WORD,490,24 +LTP093,0,19,REC_WORD,929,20 +LTP093,0,19,REC_WORD,230,21 +LTP093,0,19,REC_WORD,1511,22 +LTP093,0,19,REC_WORD,869,23 +LTP093,0,19,REC_WORD,175,19 +LTP093,0,19,REC_WORD,210,18 +LTP093,0,19,REC_WORD,490,24 +LTP093,0,19,REC_WORD,109,11 +LTP093,0,19,REC_WORD,761,12 +LTP093,0,19,REC_WORD,1096,7 +LTP093,0,19,REC_WORD,1438,8 +LTP093,0,19,REC_WORD,843,6 +LTP093,0,19,REC_WORD,601,5 +LTP093,0,19,REC_WORD,336,10 +LTP093,0,19,REC_WORD,1593,9 +LTP093,0,20,WORD,1215,1 +LTP093,0,20,WORD,610,2 +LTP093,0,20,WORD,900,3 +LTP093,0,20,WORD,1143,4 +LTP093,0,20,WORD,1357,5 +LTP093,0,20,WORD,346,6 +LTP093,0,20,WORD,1203,7 +LTP093,0,20,WORD,873,8 +LTP093,0,20,WORD,1373,9 +LTP093,0,20,WORD,46,10 +LTP093,0,20,WORD,1427,11 +LTP093,0,20,WORD,1139,12 +LTP093,0,20,WORD,783,13 +LTP093,0,20,WORD,684,14 +LTP093,0,20,WORD,467,15 +LTP093,0,20,WORD,313,16 +LTP093,0,20,WORD,1307,17 +LTP093,0,20,WORD,1555,18 +LTP093,0,20,WORD,807,19 +LTP093,0,20,WORD,1423,20 +LTP093,0,20,WORD,691,21 +LTP093,0,20,WORD,1202,22 +LTP093,0,20,WORD,1098,23 +LTP093,0,20,WORD,976,24 +LTP093,0,20,REC_WORD,1215,1 +LTP093,0,20,REC_WORD,610,2 +LTP093,0,20,REC_WORD,900,3 +LTP093,0,20,REC_WORD,1202,22 +LTP093,0,20,REC_WORD,346,6 +LTP093,0,20,REC_WORD,313,16 +LTP093,0,20,REC_WORD,1307,17 +LTP093,0,20,REC_WORD,1555,18 +LTP093,0,20,REC_WORD,467,15 +LTP093,0,21,WORD,1317,1 +LTP093,0,21,WORD,67,2 +LTP093,0,21,WORD,662,3 +LTP093,0,21,WORD,501,4 +LTP093,0,21,WORD,1019,5 +LTP093,0,21,WORD,1117,6 +LTP093,0,21,WORD,83,7 +LTP093,0,21,WORD,605,8 +LTP093,0,21,WORD,883,9 +LTP093,0,21,WORD,125,10 +LTP093,0,21,WORD,702,11 +LTP093,0,21,WORD,614,12 +LTP093,0,21,WORD,1184,13 +LTP093,0,21,WORD,752,14 +LTP093,0,21,WORD,766,15 +LTP093,0,21,WORD,6,16 +LTP093,0,21,WORD,1293,17 +LTP093,0,21,WORD,63,18 +LTP093,0,21,WORD,769,19 +LTP093,0,21,WORD,1356,20 +LTP093,0,21,WORD,804,21 +LTP093,0,21,WORD,400,22 +LTP093,0,21,WORD,1148,23 +LTP093,0,21,WORD,1572,24 +LTP093,0,21,REC_WORD,614,12 +LTP093,0,21,REC_WORD,1356,20 +LTP093,0,21,REC_WORD,804,21 +LTP093,0,21,REC_WORD,400,22 +LTP093,0,21,REC_WORD,125,10 +LTP093,0,21,REC_WORD,702,11 +LTP093,0,21,REC_WORD,662,3 +LTP093,0,21,REC_WORD,501,4 +LTP093,0,22,WORD,137,1 +LTP093,0,22,WORD,620,2 +LTP093,0,22,WORD,194,3 +LTP093,0,22,WORD,1085,4 +LTP093,0,22,WORD,795,5 +LTP093,0,22,WORD,171,6 +LTP093,0,22,WORD,1112,7 +LTP093,0,22,WORD,623,8 +LTP093,0,22,WORD,157,9 +LTP093,0,22,WORD,1051,10 +LTP093,0,22,WORD,1079,11 +LTP093,0,22,WORD,1232,12 +LTP093,0,22,WORD,569,13 +LTP093,0,22,WORD,878,14 +LTP093,0,22,WORD,1460,15 +LTP093,0,22,WORD,33,16 +LTP093,0,22,WORD,1049,17 +LTP093,0,22,WORD,265,18 +LTP093,0,22,WORD,947,19 +LTP093,0,22,WORD,1407,20 +LTP093,0,22,WORD,249,21 +LTP093,0,22,WORD,403,22 +LTP093,0,22,WORD,1037,23 +LTP093,0,22,WORD,814,24 +LTP093,0,22,REC_WORD,403,22 +LTP093,0,22,REC_WORD,1037,23 +LTP093,0,22,REC_WORD,171,6 +LTP093,0,22,REC_WORD,814,24 +LTP093,0,22,REC_WORD,947,19 +LTP093,0,22,REC_WORD,1079,11 +LTP093,0,22,REC_WORD,1232,12 +LTP093,0,23,WORD,1524,1 +LTP093,0,23,WORD,384,2 +LTP093,0,23,WORD,1347,3 +LTP093,0,23,WORD,1013,4 +LTP093,0,23,WORD,1009,5 +LTP093,0,23,WORD,849,6 +LTP093,0,23,WORD,407,7 +LTP093,0,23,WORD,476,8 +LTP093,0,23,WORD,223,9 +LTP093,0,23,WORD,1312,10 +LTP093,0,23,WORD,1626,11 +LTP093,0,23,WORD,64,12 +LTP093,0,23,WORD,1170,13 +LTP093,0,23,WORD,1048,14 +LTP093,0,23,WORD,1368,15 +LTP093,0,23,WORD,628,16 +LTP093,0,23,WORD,1416,17 +LTP093,0,23,WORD,1197,18 +LTP093,0,23,WORD,371,19 +LTP093,0,23,WORD,637,20 +LTP093,0,23,WORD,718,21 +LTP093,0,23,WORD,713,22 +LTP093,0,23,WORD,1258,23 +LTP093,0,23,WORD,308,24 +LTP093,0,23,REC_WORD,628,16 +LTP093,0,23,REC_WORD,407,7 +LTP093,0,23,REC_WORD,476,8 +LTP093,0,23,REC_WORD,64,12 +LTP093,0,24,WORD,253,1 +LTP093,0,24,WORD,955,2 +LTP093,0,24,WORD,745,3 +LTP093,0,24,WORD,427,4 +LTP093,0,24,WORD,1152,5 +LTP093,0,24,WORD,820,6 +LTP093,0,24,WORD,606,7 +LTP093,0,24,WORD,846,8 +LTP093,0,24,WORD,53,9 +LTP093,0,24,WORD,323,10 +LTP093,0,24,WORD,1173,11 +LTP093,0,24,WORD,1629,12 +LTP093,0,24,WORD,706,13 +LTP093,0,24,WORD,1024,14 +LTP093,0,24,WORD,1371,15 +LTP093,0,24,WORD,113,16 +LTP093,0,24,WORD,963,17 +LTP093,0,24,WORD,1027,18 +LTP093,0,24,WORD,1271,19 +LTP093,0,24,WORD,1501,20 +LTP093,0,24,WORD,1436,21 +LTP093,0,24,WORD,982,22 +LTP093,0,24,WORD,1044,23 +LTP093,0,24,WORD,639,24 +LTP093,0,24,REC_WORD,639,24 +LTP093,0,24,REC_WORD,982,22 +LTP093,0,24,REC_WORD,1044,23 +LTP093,0,24,REC_WORD,113,16 +LTP093,0,24,REC_WORD,963,17 +LTP093,0,24,REC_WORD,1024,14 +LTP093,0,24,REC_WORD,1371,15 +LTP093,0,24,REC_WORD,1027,18 +LTP093,0,24,REC_WORD,1271,19 +LTP093,0,24,REC_WORD,253,1 +LTP093,1,1,WORD,1355,1 +LTP093,1,1,WORD,1123,2 +LTP093,1,1,WORD,974,3 +LTP093,1,1,WORD,1356,4 +LTP093,1,1,WORD,731,5 +LTP093,1,1,WORD,1260,6 +LTP093,1,1,WORD,660,7 +LTP093,1,1,WORD,183,8 +LTP093,1,1,WORD,1148,9 +LTP093,1,1,WORD,1158,10 +LTP093,1,1,WORD,157,11 +LTP093,1,1,WORD,1098,12 +LTP093,1,1,WORD,989,13 +LTP093,1,1,WORD,304,14 +LTP093,1,1,WORD,1017,15 +LTP093,1,1,WORD,162,16 +LTP093,1,1,WORD,661,17 +LTP093,1,1,WORD,125,18 +LTP093,1,1,WORD,519,19 +LTP093,1,1,WORD,1395,20 +LTP093,1,1,WORD,782,21 +LTP093,1,1,WORD,485,22 +LTP093,1,1,WORD,1496,23 +LTP093,1,1,WORD,715,24 +LTP093,1,1,REC_WORD,1355,1 +LTP093,1,1,REC_WORD,1123,2 +LTP093,1,1,REC_WORD,1148,9 +LTP093,1,1,REC_WORD,1158,10 +LTP093,1,1,REC_WORD,1395,20 +LTP093,1,1,REC_WORD,519,19 +LTP093,1,1,REC_WORD,660,7 +LTP093,1,1,REC_WORD,183,8 +LTP093,1,1,REC_WORD,782,21 +LTP093,1,1,REC_WORD,162,16 +LTP093,1,1,REC_WORD,974,3 +LTP093,1,2,WORD,1170,1 +LTP093,1,2,WORD,390,2 +LTP093,1,2,WORD,1229,3 +LTP093,1,2,WORD,439,4 +LTP093,1,2,WORD,295,5 +LTP093,1,2,WORD,1544,6 +LTP093,1,2,WORD,1065,7 +LTP093,1,2,WORD,963,8 +LTP093,1,2,WORD,682,9 +LTP093,1,2,WORD,1307,10 +LTP093,1,2,WORD,1261,11 +LTP093,1,2,WORD,1341,12 +LTP093,1,2,WORD,5,13 +LTP093,1,2,WORD,737,14 +LTP093,1,2,WORD,177,15 +LTP093,1,2,WORD,1238,16 +LTP093,1,2,WORD,203,17 +LTP093,1,2,WORD,1224,18 +LTP093,1,2,WORD,814,19 +LTP093,1,2,WORD,292,20 +LTP093,1,2,WORD,488,21 +LTP093,1,2,WORD,1426,22 +LTP093,1,2,WORD,83,23 +LTP093,1,2,WORD,579,24 +LTP093,1,2,REC_WORD,203,17 +LTP093,1,2,REC_WORD,1238,16 +LTP093,1,2,REC_WORD,1224,18 +LTP093,1,2,REC_WORD,814,19 +LTP093,1,2,REC_WORD,963,8 +LTP093,1,2,REC_WORD,1065,7 +LTP093,1,2,REC_WORD,292,20 +LTP093,1,2,REC_WORD,488,21 +LTP093,1,2,REC_WORD,1229,3 +LTP093,1,2,REC_WORD,439,4 +LTP093,1,2,REC_WORD,295,5 +LTP093,1,2,REC_WORD,1544,6 +LTP093,1,3,WORD,1605,1 +LTP093,1,3,WORD,1620,2 +LTP093,1,3,WORD,373,3 +LTP093,1,3,WORD,827,4 +LTP093,1,3,WORD,1282,5 +LTP093,1,3,WORD,386,6 +LTP093,1,3,WORD,999,7 +LTP093,1,3,WORD,343,8 +LTP093,1,3,WORD,134,9 +LTP093,1,3,WORD,1275,10 +LTP093,1,3,WORD,602,11 +LTP093,1,3,WORD,1565,12 +LTP093,1,3,WORD,929,13 +LTP093,1,3,WORD,849,14 +LTP093,1,3,WORD,1411,15 +LTP093,1,3,WORD,585,16 +LTP093,1,3,WORD,1036,17 +LTP093,1,3,WORD,1315,18 +LTP093,1,3,WORD,1176,19 +LTP093,1,3,WORD,1629,20 +LTP093,1,3,WORD,1070,21 +LTP093,1,3,WORD,1545,22 +LTP093,1,3,WORD,1328,23 +LTP093,1,3,WORD,447,24 +LTP093,1,3,REC_WORD,134,9 +LTP093,1,3,REC_WORD,1275,10 +LTP093,1,4,WORD,988,1 +LTP093,1,4,WORD,1124,2 +LTP093,1,4,WORD,1111,3 +LTP093,1,4,WORD,1155,4 +LTP093,1,4,WORD,783,5 +LTP093,1,4,WORD,1060,6 +LTP093,1,4,WORD,1002,7 +LTP093,1,4,WORD,1271,8 +LTP093,1,4,WORD,143,9 +LTP093,1,4,WORD,1349,10 +LTP093,1,4,WORD,137,11 +LTP093,1,4,WORD,10,12 +LTP093,1,4,WORD,1420,13 +LTP093,1,4,WORD,1370,14 +LTP093,1,4,WORD,997,15 +LTP093,1,4,WORD,670,16 +LTP093,1,4,WORD,360,17 +LTP093,1,4,WORD,119,18 +LTP093,1,4,WORD,1451,19 +LTP093,1,4,WORD,267,20 +LTP093,1,4,WORD,980,21 +LTP093,1,4,WORD,216,22 +LTP093,1,4,WORD,618,23 +LTP093,1,4,WORD,746,24 +LTP093,1,4,REC_WORD,1271,8 +LTP093,1,4,REC_WORD,1002,7 +LTP093,1,4,REC_WORD,1124,2 +LTP093,1,4,REC_WORD,988,1 +LTP093,1,4,REC_WORD,1111,3 +LTP093,1,4,REC_WORD,1060,6 +LTP093,1,4,REC_WORD,1155,4 +LTP093,1,4,REC_WORD,783,5 +LTP093,1,5,WORD,496,1 +LTP093,1,5,WORD,397,2 +LTP093,1,5,WORD,738,3 +LTP093,1,5,WORD,766,4 +LTP093,1,5,WORD,623,5 +LTP093,1,5,WORD,1280,6 +LTP093,1,5,WORD,1331,7 +LTP093,1,5,WORD,429,8 +LTP093,1,5,WORD,1295,9 +LTP093,1,5,WORD,1415,10 +LTP093,1,5,WORD,1592,11 +LTP093,1,5,WORD,353,12 +LTP093,1,5,WORD,707,13 +LTP093,1,5,WORD,1303,14 +LTP093,1,5,WORD,793,15 +LTP093,1,5,WORD,1203,16 +LTP093,1,5,WORD,348,17 +LTP093,1,5,WORD,166,18 +LTP093,1,5,WORD,976,19 +LTP093,1,5,WORD,1511,20 +LTP093,1,5,WORD,446,21 +LTP093,1,5,WORD,495,22 +LTP093,1,5,WORD,199,23 +LTP093,1,5,WORD,888,24 +LTP093,1,5,REC_WORD,397,2 +LTP093,1,5,REC_WORD,496,1 +LTP093,1,5,REC_WORD,199,23 +LTP093,1,5,REC_WORD,1280,6 +LTP093,1,5,REC_WORD,429,8 +LTP093,1,5,REC_WORD,1295,9 +LTP093,1,5,REC_WORD,738,3 +LTP093,1,5,REC_WORD,1415,10 +LTP093,1,5,REC_WORD,766,4 +LTP093,1,5,REC_WORD,707,13 +LTP093,1,5,REC_WORD,1303,14 +LTP093,1,5,REC_WORD,353,12 +LTP093,1,5,REC_WORD,348,17 +LTP093,1,5,REC_WORD,1203,16 +LTP093,1,5,REC_WORD,166,18 +LTP093,1,5,REC_WORD,446,21 +LTP093,1,5,REC_WORD,495,22 +LTP093,1,6,WORD,1438,1 +LTP093,1,6,WORD,708,2 +LTP093,1,6,WORD,1505,3 +LTP093,1,6,WORD,937,4 +LTP093,1,6,WORD,1089,5 +LTP093,1,6,WORD,620,6 +LTP093,1,6,WORD,796,7 +LTP093,1,6,WORD,94,8 +LTP093,1,6,WORD,901,9 +LTP093,1,6,WORD,955,10 +LTP093,1,6,WORD,1371,11 +LTP093,1,6,WORD,600,12 +LTP093,1,6,WORD,1611,13 +LTP093,1,6,WORD,499,14 +LTP093,1,6,WORD,254,15 +LTP093,1,6,WORD,908,16 +LTP093,1,6,WORD,437,17 +LTP093,1,6,WORD,1173,18 +LTP093,1,6,WORD,84,19 +LTP093,1,6,WORD,622,20 +LTP093,1,6,WORD,1092,21 +LTP093,1,6,WORD,400,22 +LTP093,1,6,WORD,1088,23 +LTP093,1,6,WORD,1557,24 +LTP093,1,6,REC_WORD,1092,21 +LTP093,1,6,REC_WORD,400,22 +LTP093,1,6,REC_WORD,1557,24 +LTP093,1,6,REC_WORD,84,19 +LTP093,1,6,REC_WORD,908,16 +LTP093,1,6,REC_WORD,437,17 +LTP093,1,6,REC_WORD,1173,18 +LTP093,1,6,REC_WORD,254,15 +LTP093,1,6,REC_WORD,499,14 +LTP093,1,6,REC_WORD,622,20 +LTP093,1,6,REC_WORD,1089,5 +LTP093,1,6,REC_WORD,620,6 +LTP093,1,6,REC_WORD,1371,11 +LTP093,1,6,REC_WORD,1611,13 +LTP093,1,6,REC_WORD,600,12 +LTP093,1,7,WORD,637,1 +LTP093,1,7,WORD,280,2 +LTP093,1,7,WORD,1448,3 +LTP093,1,7,WORD,1071,4 +LTP093,1,7,WORD,164,5 +LTP093,1,7,WORD,508,6 +LTP093,1,7,WORD,1416,7 +LTP093,1,7,WORD,63,8 +LTP093,1,7,WORD,24,9 +LTP093,1,7,WORD,308,10 +LTP093,1,7,WORD,75,11 +LTP093,1,7,WORD,1427,12 +LTP093,1,7,WORD,1209,13 +LTP093,1,7,WORD,1382,14 +LTP093,1,7,WORD,1440,15 +LTP093,1,7,WORD,1140,16 +LTP093,1,7,WORD,798,17 +LTP093,1,7,WORD,223,18 +LTP093,1,7,WORD,410,19 +LTP093,1,7,WORD,1530,20 +LTP093,1,7,WORD,1159,21 +LTP093,1,7,WORD,1125,22 +LTP093,1,7,WORD,543,23 +LTP093,1,7,WORD,1172,24 +LTP093,1,7,REC_WORD,637,1 +LTP093,1,7,REC_WORD,280,2 +LTP093,1,7,REC_WORD,1448,3 +LTP093,1,7,REC_WORD,1071,4 +LTP093,1,7,REC_WORD,164,5 +LTP093,1,7,REC_WORD,508,6 +LTP093,1,7,REC_WORD,308,10 +LTP093,1,7,REC_WORD,1416,7 +LTP093,1,7,REC_WORD,63,8 +LTP093,1,7,REC_WORD,75,11 +LTP093,1,7,REC_WORD,1427,12 +LTP093,1,7,REC_WORD,1440,15 +LTP093,1,7,REC_WORD,1140,16 +LTP093,1,7,REC_WORD,1530,20 +LTP093,1,7,REC_WORD,1159,21 +LTP093,1,8,WORD,1035,1 +LTP093,1,8,WORD,1113,2 +LTP093,1,8,WORD,1032,3 +LTP093,1,8,WORD,1358,4 +LTP093,1,8,WORD,553,5 +LTP093,1,8,WORD,763,6 +LTP093,1,8,WORD,675,7 +LTP093,1,8,WORD,1184,8 +LTP093,1,8,WORD,466,9 +LTP093,1,8,WORD,389,10 +LTP093,1,8,WORD,1330,11 +LTP093,1,8,WORD,131,12 +LTP093,1,8,WORD,1385,13 +LTP093,1,8,WORD,760,14 +LTP093,1,8,WORD,1521,15 +LTP093,1,8,WORD,1143,16 +LTP093,1,8,WORD,761,17 +LTP093,1,8,WORD,919,18 +LTP093,1,8,WORD,184,19 +LTP093,1,8,WORD,745,20 +LTP093,1,8,WORD,401,21 +LTP093,1,8,WORD,598,22 +LTP093,1,8,WORD,776,23 +LTP093,1,8,WORD,1533,24 +LTP093,1,8,REC_WORD,1533,24 +LTP093,1,8,REC_WORD,760,14 +LTP093,1,8,REC_WORD,1385,13 +LTP093,1,8,REC_WORD,-1,-999 +LTP093,1,9,WORD,723,1 +LTP093,1,9,WORD,1581,2 +LTP093,1,9,WORD,689,3 +LTP093,1,9,WORD,1117,4 +LTP093,1,9,WORD,299,5 +LTP093,1,9,WORD,1027,6 +LTP093,1,9,WORD,1079,7 +LTP093,1,9,WORD,1501,8 +LTP093,1,9,WORD,972,9 +LTP093,1,9,WORD,198,10 +LTP093,1,9,WORD,1044,11 +LTP093,1,9,WORD,843,12 +LTP093,1,9,WORD,829,13 +LTP093,1,9,WORD,769,14 +LTP093,1,9,WORD,840,15 +LTP093,1,9,WORD,346,16 +LTP093,1,9,WORD,1532,17 +LTP093,1,9,WORD,441,18 +LTP093,1,9,WORD,1345,19 +LTP093,1,9,WORD,1373,20 +LTP093,1,9,WORD,726,21 +LTP093,1,9,WORD,476,22 +LTP093,1,9,WORD,1312,23 +LTP093,1,9,WORD,696,24 +LTP093,1,9,REC_WORD,723,1 +LTP093,1,9,REC_WORD,1581,2 +LTP093,1,9,REC_WORD,198,10 +LTP093,1,9,REC_WORD,1044,11 +LTP093,1,9,REC_WORD,1501,8 +LTP093,1,9,REC_WORD,696,24 +LTP093,1,9,REC_WORD,726,21 +LTP093,1,9,REC_WORD,476,22 +LTP093,1,9,REC_WORD,1312,23 +LTP093,1,10,WORD,1562,1 +LTP093,1,10,WORD,755,2 +LTP093,1,10,WORD,1333,3 +LTP093,1,10,WORD,235,4 +LTP093,1,10,WORD,1057,5 +LTP093,1,10,WORD,1515,6 +LTP093,1,10,WORD,395,7 +LTP093,1,10,WORD,425,8 +LTP093,1,10,WORD,1152,9 +LTP093,1,10,WORD,1093,10 +LTP093,1,10,WORD,384,11 +LTP093,1,10,WORD,230,12 +LTP093,1,10,WORD,1519,13 +LTP093,1,10,WORD,846,14 +LTP093,1,10,WORD,1048,15 +LTP093,1,10,WORD,1221,16 +LTP093,1,10,WORD,1329,17 +LTP093,1,10,WORD,800,18 +LTP093,1,10,WORD,1520,19 +LTP093,1,10,WORD,1478,20 +LTP093,1,10,WORD,1608,21 +LTP093,1,10,WORD,210,22 +LTP093,1,10,WORD,1578,23 +LTP093,1,10,WORD,249,24 +LTP093,1,10,REC_WORD,210,22 +LTP093,1,10,REC_WORD,1520,19 +LTP093,1,10,REC_WORD,1478,20 +LTP093,1,10,REC_WORD,1608,21 +LTP093,1,10,REC_WORD,1333,3 +LTP093,1,10,REC_WORD,755,2 +LTP093,1,10,REC_WORD,1562,1 +LTP093,1,10,REC_WORD,1329,17 +LTP093,1,10,REC_WORD,800,18 +LTP093,1,10,REC_WORD,1152,9 +LTP093,1,11,WORD,569,1 +LTP093,1,11,WORD,1392,2 +LTP093,1,11,WORD,100,3 +LTP093,1,11,WORD,658,4 +LTP093,1,11,WORD,1232,5 +LTP093,1,11,WORD,1095,6 +LTP093,1,11,WORD,498,7 +LTP093,1,11,WORD,1006,8 +LTP093,1,11,WORD,1461,9 +LTP093,1,11,WORD,1096,10 +LTP093,1,11,WORD,403,11 +LTP093,1,11,WORD,718,12 +LTP093,1,11,WORD,139,13 +LTP093,1,11,WORD,1171,14 +LTP093,1,11,WORD,278,15 +LTP093,1,11,WORD,1460,16 +LTP093,1,11,WORD,1022,17 +LTP093,1,11,WORD,1242,18 +LTP093,1,11,WORD,67,19 +LTP093,1,11,WORD,935,20 +LTP093,1,11,WORD,1422,21 +LTP093,1,11,WORD,431,22 +LTP093,1,11,WORD,861,23 +LTP093,1,11,WORD,1251,24 +LTP093,1,11,REC_WORD,1242,18 +LTP093,1,11,REC_WORD,935,20 +LTP093,1,11,REC_WORD,67,19 +LTP093,1,11,REC_WORD,100,3 +LTP093,1,11,REC_WORD,658,4 +LTP093,1,11,REC_WORD,861,23 +LTP093,1,12,WORD,142,1 +LTP093,1,12,WORD,211,2 +LTP093,1,12,WORD,240,3 +LTP093,1,12,WORD,490,4 +LTP093,1,12,WORD,1403,5 +LTP093,1,12,WORD,839,6 +LTP093,1,12,WORD,442,7 +LTP093,1,12,WORD,494,8 +LTP093,1,12,WORD,226,9 +LTP093,1,12,WORD,719,10 +LTP093,1,12,WORD,492,11 +LTP093,1,12,WORD,1536,12 +LTP093,1,12,WORD,895,13 +LTP093,1,12,WORD,792,14 +LTP093,1,12,WORD,1287,15 +LTP093,1,12,WORD,484,16 +LTP093,1,12,WORD,1085,17 +LTP093,1,12,WORD,866,18 +LTP093,1,12,WORD,520,19 +LTP093,1,12,WORD,175,20 +LTP093,1,12,WORD,307,21 +LTP093,1,12,WORD,605,22 +LTP093,1,12,WORD,809,23 +LTP093,1,12,WORD,316,24 +LTP093,1,12,REC_WORD,809,23 +LTP093,1,12,REC_WORD,316,24 +LTP093,1,12,REC_WORD,307,21 +LTP093,1,12,REC_WORD,605,22 +LTP093,1,12,REC_WORD,1536,12 +LTP093,1,12,REC_WORD,492,11 +LTP093,1,12,REC_WORD,719,10 +LTP093,1,12,REC_WORD,226,9 +LTP093,1,12,REC_WORD,442,7 +LTP093,1,12,REC_WORD,494,8 +LTP093,1,12,REC_WORD,142,1 +LTP093,1,12,REC_WORD,211,2 +LTP093,1,12,REC_WORD,839,6 +LTP093,1,12,REC_WORD,240,3 +LTP093,1,12,REC_WORD,490,4 +LTP093,1,12,REC_WORD,175,20 +LTP093,1,13,WORD,372,1 +LTP093,1,13,WORD,820,2 +LTP093,1,13,WORD,1343,3 +LTP093,1,13,WORD,1246,4 +LTP093,1,13,WORD,873,5 +LTP093,1,13,WORD,654,6 +LTP093,1,13,WORD,1256,7 +LTP093,1,13,WORD,82,8 +LTP093,1,13,WORD,388,9 +LTP093,1,13,WORD,559,10 +LTP093,1,13,WORD,592,11 +LTP093,1,13,WORD,702,12 +LTP093,1,13,WORD,1626,13 +LTP093,1,13,WORD,871,14 +LTP093,1,13,WORD,1388,15 +LTP093,1,13,WORD,1535,16 +LTP093,1,13,WORD,691,17 +LTP093,1,13,WORD,168,18 +LTP093,1,13,WORD,982,19 +LTP093,1,13,WORD,1488,20 +LTP093,1,13,WORD,847,21 +LTP093,1,13,WORD,771,22 +LTP093,1,13,WORD,1369,23 +LTP093,1,13,WORD,248,24 +LTP093,1,13,REC_WORD,1388,15 +LTP093,1,13,REC_WORD,1535,16 +LTP093,1,13,REC_WORD,873,5 +LTP093,1,13,REC_WORD,654,6 +LTP093,1,13,REC_WORD,691,17 +LTP093,1,13,REC_WORD,168,18 +LTP093,1,14,WORD,576,1 +LTP093,1,14,WORD,922,2 +LTP093,1,14,WORD,408,3 +LTP093,1,14,WORD,1119,4 +LTP093,1,14,WORD,546,5 +LTP093,1,14,WORD,258,6 +LTP093,1,14,WORD,778,7 +LTP093,1,14,WORD,1087,8 +LTP093,1,14,WORD,109,9 +LTP093,1,14,WORD,108,10 +LTP093,1,14,WORD,415,11 +LTP093,1,14,WORD,1049,12 +LTP093,1,14,WORD,1326,13 +LTP093,1,14,WORD,795,14 +LTP093,1,14,WORD,313,15 +LTP093,1,14,WORD,340,16 +LTP093,1,14,WORD,1299,17 +LTP093,1,14,WORD,764,18 +LTP093,1,14,WORD,338,19 +LTP093,1,14,WORD,684,20 +LTP093,1,14,WORD,1199,21 +LTP093,1,14,WORD,590,22 +LTP093,1,14,WORD,1194,23 +LTP093,1,14,WORD,512,24 +LTP093,1,14,REC_WORD,1199,21 +LTP093,1,14,REC_WORD,590,22 +LTP093,1,14,REC_WORD,778,7 +LTP093,1,14,REC_WORD,1087,8 +LTP093,1,15,WORD,1009,1 +LTP093,1,15,WORD,878,2 +LTP093,1,15,WORD,666,3 +LTP093,1,15,WORD,1524,4 +LTP093,1,15,WORD,1197,5 +LTP093,1,15,WORD,858,6 +LTP093,1,15,WORD,194,7 +LTP093,1,15,WORD,1508,8 +LTP093,1,15,WORD,561,9 +LTP093,1,15,WORD,35,10 +LTP093,1,15,WORD,1609,11 +LTP093,1,15,WORD,1019,12 +LTP093,1,15,WORD,68,13 +LTP093,1,15,WORD,812,14 +LTP093,1,15,WORD,1527,15 +LTP093,1,15,WORD,61,16 +LTP093,1,15,WORD,659,17 +LTP093,1,15,WORD,662,18 +LTP093,1,15,WORD,64,19 +LTP093,1,15,WORD,885,20 +LTP093,1,15,WORD,940,21 +LTP093,1,15,WORD,1011,22 +LTP093,1,15,WORD,790,23 +LTP093,1,15,WORD,1319,24 +LTP093,1,15,REC_WORD,1197,5 +LTP093,1,15,REC_WORD,194,7 +LTP093,1,15,REC_WORD,1508,8 +LTP093,1,15,REC_WORD,1609,11 +LTP093,1,15,REC_WORD,35,10 +LTP093,1,15,REC_WORD,1009,1 +LTP093,1,15,REC_WORD,812,14 +LTP093,1,15,REC_WORD,1527,15 +LTP093,1,15,REC_WORD,878,2 +LTP093,1,16,WORD,405,1 +LTP093,1,16,WORD,497,2 +LTP093,1,16,WORD,1132,3 +LTP093,1,16,WORD,1622,4 +LTP093,1,16,WORD,916,5 +LTP093,1,16,WORD,91,6 +LTP093,1,16,WORD,127,7 +LTP093,1,16,WORD,1258,8 +LTP093,1,16,WORD,724,9 +LTP093,1,16,WORD,1144,10 +LTP093,1,16,WORD,593,11 +LTP093,1,16,WORD,584,12 +LTP093,1,16,WORD,1080,13 +LTP093,1,16,WORD,1636,14 +LTP093,1,16,WORD,977,15 +LTP093,1,16,WORD,1200,16 +LTP093,1,16,WORD,1374,17 +LTP093,1,16,WORD,1021,18 +LTP093,1,16,WORD,575,19 +LTP093,1,16,WORD,1468,20 +LTP093,1,16,WORD,699,21 +LTP093,1,16,WORD,1546,22 +LTP093,1,16,WORD,1037,23 +LTP093,1,16,WORD,255,24 +LTP093,1,16,REC_WORD,699,21 +LTP093,1,16,REC_WORD,1546,22 +LTP093,1,16,REC_WORD,1037,23 +LTP093,1,16,REC_WORD,255,24 +LTP093,1,16,REC_WORD,724,9 +LTP093,1,16,REC_WORD,1144,10 +LTP093,1,16,REC_WORD,1132,3 +LTP093,1,16,REC_WORD,1622,4 +LTP093,1,16,REC_WORD,584,12 +LTP093,1,16,REC_WORD,977,15 +LTP093,1,16,REC_WORD,1374,17 +LTP093,1,16,REC_WORD,1258,8 +LTP093,1,16,REC_WORD,1021,18 +LTP093,1,16,REC_WORD,1200,16 +LTP093,1,17,WORD,1243,1 +LTP093,1,17,WORD,1635,2 +LTP093,1,17,WORD,435,3 +LTP093,1,17,WORD,601,4 +LTP093,1,17,WORD,642,5 +LTP093,1,17,WORD,947,6 +LTP093,1,17,WORD,1024,7 +LTP093,1,17,WORD,1347,8 +LTP093,1,17,WORD,728,9 +LTP093,1,17,WORD,392,10 +LTP093,1,17,WORD,1301,11 +LTP093,1,17,WORD,1112,12 +LTP093,1,17,WORD,994,13 +LTP093,1,17,WORD,960,14 +LTP093,1,17,WORD,641,15 +LTP093,1,17,WORD,6,16 +LTP093,1,17,WORD,169,17 +LTP093,1,17,WORD,483,18 +LTP093,1,17,WORD,580,19 +LTP093,1,17,WORD,1400,20 +LTP093,1,17,WORD,55,21 +LTP093,1,17,WORD,987,22 +LTP093,1,17,WORD,706,23 +LTP093,1,17,WORD,1245,24 +LTP093,1,17,REC_WORD,1245,24 +LTP093,1,17,REC_WORD,706,23 +LTP093,1,17,REC_WORD,1243,1 +LTP093,1,17,REC_WORD,1635,2 +LTP093,1,17,REC_WORD,435,3 +LTP093,1,17,REC_WORD,601,4 +LTP093,1,17,REC_WORD,947,6 +LTP093,1,17,REC_WORD,642,5 +LTP093,1,17,REC_WORD,55,21 +LTP093,1,17,REC_WORD,483,18 +LTP093,1,17,REC_WORD,580,19 +LTP093,1,17,REC_WORD,1347,8 +LTP093,1,17,REC_WORD,728,9 +LTP093,1,17,REC_WORD,1301,11 +LTP093,1,18,WORD,88,1 +LTP093,1,18,WORD,624,2 +LTP093,1,18,WORD,1472,3 +LTP093,1,18,WORD,1076,4 +LTP093,1,18,WORD,1219,5 +LTP093,1,18,WORD,628,6 +LTP093,1,18,WORD,1147,7 +LTP093,1,18,WORD,1015,8 +LTP093,1,18,WORD,413,9 +LTP093,1,18,WORD,1384,10 +LTP093,1,18,WORD,567,11 +LTP093,1,18,WORD,752,12 +LTP093,1,18,WORD,804,13 +LTP093,1,18,WORD,368,14 +LTP093,1,18,WORD,1183,15 +LTP093,1,18,WORD,785,16 +LTP093,1,18,WORD,1061,17 +LTP093,1,18,WORD,509,18 +LTP093,1,18,WORD,1572,19 +LTP093,1,18,WORD,614,20 +LTP093,1,18,WORD,1456,21 +LTP093,1,18,WORD,683,22 +LTP093,1,18,WORD,159,23 +LTP093,1,18,WORD,1047,24 +LTP093,1,18,REC_WORD,1047,24 +LTP093,1,18,REC_WORD,159,23 +LTP093,1,18,REC_WORD,1183,15 +LTP093,1,18,REC_WORD,683,22 +LTP093,1,18,REC_WORD,1219,5 +LTP093,1,18,REC_WORD,628,6 +LTP093,1,18,REC_WORD,1384,10 +LTP093,1,18,REC_WORD,567,11 +LTP093,1,18,REC_WORD,624,2 +LTP093,1,18,REC_WORD,88,1 +LTP093,1,19,WORD,900,1 +LTP093,1,19,WORD,39,2 +LTP093,1,19,WORD,1408,3 +LTP093,1,19,WORD,633,4 +LTP093,1,19,WORD,1621,5 +LTP093,1,19,WORD,315,6 +LTP093,1,19,WORD,1512,7 +LTP093,1,19,WORD,1555,8 +LTP093,1,19,WORD,358,9 +LTP093,1,19,WORD,1250,10 +LTP093,1,19,WORD,1407,11 +LTP093,1,19,WORD,749,12 +LTP093,1,19,WORD,541,13 +LTP093,1,19,WORD,29,14 +LTP093,1,19,WORD,639,15 +LTP093,1,19,WORD,714,16 +LTP093,1,19,WORD,893,17 +LTP093,1,19,WORD,1503,18 +LTP093,1,19,WORD,53,19 +LTP093,1,19,WORD,12,20 +LTP093,1,19,WORD,1633,21 +LTP093,1,19,WORD,1317,22 +LTP093,1,19,WORD,1293,23 +LTP093,1,19,WORD,1522,24 +LTP093,1,19,REC_WORD,1317,22 +LTP093,1,19,REC_WORD,749,12 +LTP093,1,19,REC_WORD,541,13 +LTP093,1,19,REC_WORD,1503,18 +LTP093,1,19,REC_WORD,893,17 +LTP093,1,19,REC_WORD,1407,11 +LTP093,1,19,REC_WORD,1408,3 +LTP093,1,19,REC_WORD,633,4 +LTP093,1,19,REC_WORD,714,16 +LTP093,1,20,WORD,1357,1 +LTP093,1,20,WORD,834,2 +LTP093,1,20,WORD,1351,3 +LTP093,1,20,WORD,171,4 +LTP093,1,20,WORD,253,5 +LTP093,1,20,WORD,200,6 +LTP093,1,20,WORD,801,7 +LTP093,1,20,WORD,645,8 +LTP093,1,20,WORD,86,9 +LTP093,1,20,WORD,1436,10 +LTP093,1,20,WORD,378,11 +LTP093,1,20,WORD,635,12 +LTP093,1,20,WORD,857,13 +LTP093,1,20,WORD,1486,14 +LTP093,1,20,WORD,1332,15 +LTP093,1,20,WORD,912,16 +LTP093,1,20,WORD,1631,17 +LTP093,1,20,WORD,407,18 +LTP093,1,20,WORD,336,19 +LTP093,1,20,WORD,38,20 +LTP093,1,20,WORD,417,21 +LTP093,1,20,WORD,874,22 +LTP093,1,20,WORD,187,23 +LTP093,1,20,WORD,732,24 +LTP093,1,20,REC_WORD,1357,1 +LTP093,1,20,REC_WORD,834,2 +LTP093,1,20,REC_WORD,1351,3 +LTP093,1,20,REC_WORD,171,4 +LTP093,1,20,REC_WORD,801,7 +LTP093,1,20,REC_WORD,645,8 +LTP093,1,21,WORD,1262,1 +LTP093,1,21,WORD,833,2 +LTP093,1,21,WORD,932,3 +LTP093,1,21,WORD,754,4 +LTP093,1,21,WORD,570,5 +LTP093,1,21,WORD,172,6 +LTP093,1,21,WORD,1227,7 +LTP093,1,21,WORD,1013,8 +LTP093,1,21,WORD,995,9 +LTP093,1,21,WORD,852,10 +LTP093,1,21,WORD,667,11 +LTP093,1,21,WORD,959,12 +LTP093,1,21,WORD,1139,13 +LTP093,1,21,WORD,113,14 +LTP093,1,21,WORD,136,15 +LTP093,1,21,WORD,573,16 +LTP093,1,21,WORD,1192,17 +LTP093,1,21,WORD,1051,18 +LTP093,1,21,WORD,66,19 +LTP093,1,21,WORD,872,20 +LTP093,1,21,WORD,327,21 +LTP093,1,21,WORD,1587,22 +LTP093,1,21,WORD,578,23 +LTP093,1,21,WORD,697,24 +LTP093,1,21,REC_WORD,578,23 +LTP093,1,21,REC_WORD,697,24 +LTP093,1,21,REC_WORD,959,12 +LTP093,1,21,REC_WORD,667,11 +LTP093,1,21,REC_WORD,1139,13 +LTP093,1,21,REC_WORD,113,14 +LTP093,1,21,REC_WORD,754,4 +LTP093,1,21,REC_WORD,932,3 +LTP093,1,21,REC_WORD,995,9 +LTP093,1,21,REC_WORD,852,10 +LTP093,1,22,WORD,1618,1 +LTP093,1,22,WORD,1606,2 +LTP093,1,22,WORD,341,3 +LTP093,1,22,WORD,13,4 +LTP093,1,22,WORD,734,5 +LTP093,1,22,WORD,604,6 +LTP093,1,22,WORD,807,7 +LTP093,1,22,WORD,133,8 +LTP093,1,22,WORD,599,9 +LTP093,1,22,WORD,530,10 +LTP093,1,22,WORD,869,11 +LTP093,1,22,WORD,1000,12 +LTP093,1,22,WORD,323,13 +LTP093,1,22,WORD,1086,14 +LTP093,1,22,WORD,627,15 +LTP093,1,22,WORD,794,16 +LTP093,1,22,WORD,1405,17 +LTP093,1,22,WORD,427,18 +LTP093,1,22,WORD,1493,19 +LTP093,1,22,WORD,188,20 +LTP093,1,22,WORD,33,21 +LTP093,1,22,WORD,1628,22 +LTP093,1,22,WORD,1149,23 +LTP093,1,22,WORD,1016,24 +LTP093,1,22,REC_WORD,1618,1 +LTP093,1,22,REC_WORD,1606,2 +LTP093,1,22,REC_WORD,341,3 +LTP093,1,22,REC_WORD,807,7 +LTP093,1,22,REC_WORD,1405,17 +LTP093,1,22,REC_WORD,133,8 +LTP093,1,22,REC_WORD,599,9 +LTP093,1,22,REC_WORD,869,11 +LTP093,1,23,WORD,996,1 +LTP093,1,23,WORD,565,2 +LTP093,1,23,WORD,848,3 +LTP093,1,23,WORD,1368,4 +LTP093,1,23,WORD,1414,5 +LTP093,1,23,WORD,179,6 +LTP093,1,23,WORD,1294,7 +LTP093,1,23,WORD,46,8 +LTP093,1,23,WORD,606,9 +LTP093,1,23,WORD,104,10 +LTP093,1,23,WORD,145,11 +LTP093,1,23,WORD,501,12 +LTP093,1,23,WORD,733,13 +LTP093,1,23,WORD,1580,14 +LTP093,1,23,WORD,1423,15 +LTP093,1,23,WORD,1202,16 +LTP093,1,23,WORD,713,17 +LTP093,1,23,WORD,1593,18 +LTP093,1,23,WORD,692,19 +LTP093,1,23,WORD,339,20 +LTP093,1,23,WORD,1292,21 +LTP093,1,23,WORD,328,22 +LTP093,1,23,WORD,1108,23 +LTP093,1,23,WORD,610,24 +LTP093,1,23,REC_WORD,692,19 +LTP093,1,23,REC_WORD,339,20 +LTP093,1,23,REC_WORD,1292,21 +LTP093,1,23,REC_WORD,713,17 +LTP093,1,23,REC_WORD,1593,18 +LTP093,1,23,REC_WORD,1294,7 +LTP093,1,23,REC_WORD,46,8 +LTP093,1,23,REC_WORD,606,9 +LTP093,1,23,REC_WORD,1423,15 +LTP093,1,23,REC_WORD,1202,16 +LTP093,1,23,REC_WORD,328,22 +LTP093,1,23,REC_WORD,996,1 +LTP093,1,23,REC_WORD,565,2 +LTP093,1,23,REC_WORD,848,3 +LTP093,1,23,REC_WORD,1368,4 +LTP093,1,24,WORD,821,1 +LTP093,1,24,WORD,953,2 +LTP093,1,24,WORD,1327,3 +LTP093,1,24,WORD,467,4 +LTP093,1,24,WORD,1625,5 +LTP093,1,24,WORD,883,6 +LTP093,1,24,WORD,879,7 +LTP093,1,24,WORD,1104,8 +LTP093,1,24,WORD,265,9 +LTP093,1,24,WORD,1215,10 +LTP093,1,24,WORD,1075,11 +LTP093,1,24,WORD,870,12 +LTP093,1,24,WORD,1066,13 +LTP093,1,24,WORD,591,14 +LTP093,1,24,WORD,283,15 +LTP093,1,24,WORD,383,16 +LTP093,1,24,WORD,1272,17 +LTP093,1,24,WORD,261,18 +LTP093,1,24,WORD,325,19 +LTP093,1,24,WORD,371,20 +LTP093,1,24,WORD,1031,21 +LTP093,1,24,WORD,876,22 +LTP093,1,24,WORD,1526,23 +LTP093,1,24,WORD,1284,24 +LTP093,1,24,REC_WORD,821,1 +LTP093,1,24,REC_WORD,953,2 +LTP093,1,24,REC_WORD,1284,24 +LTP093,1,24,REC_WORD,1526,23 +LTP093,1,24,REC_WORD,325,19 +LTP093,1,24,REC_WORD,1215,10 +LTP093,1,24,REC_WORD,1066,13 +LTP093,1,24,REC_WORD,591,14 +LTP093,1,24,REC_WORD,383,16 +LTP093,1,24,REC_WORD,1272,17 +LTP093,1,24,REC_WORD,261,18 +LTP093,1,24,REC_WORD,1327,3 +LTP093,1,24,REC_WORD,467,4 +LTP093,2,1,WORD,585,1 +LTP093,2,1,WORD,509,2 +LTP093,2,1,WORD,666,3 +LTP093,2,1,WORD,1355,4 +LTP093,2,1,WORD,706,5 +LTP093,2,1,WORD,599,6 +LTP093,2,1,WORD,746,7 +LTP093,2,1,WORD,1327,8 +LTP093,2,1,WORD,827,9 +LTP093,2,1,WORD,336,10 +LTP093,2,1,WORD,1333,11 +LTP093,2,1,WORD,576,12 +LTP093,2,1,WORD,610,13 +LTP093,2,1,WORD,230,14 +LTP093,2,1,WORD,1349,15 +LTP093,2,1,WORD,249,16 +LTP093,2,1,WORD,1408,17 +LTP093,2,1,WORD,226,18 +LTP093,2,1,WORD,999,19 +LTP093,2,1,WORD,283,20 +LTP093,2,1,WORD,893,21 +LTP093,2,1,WORD,360,22 +LTP093,2,1,WORD,408,23 +LTP093,2,1,WORD,339,24 +LTP093,2,1,REC_WORD,585,1 +LTP093,2,1,REC_WORD,509,2 +LTP093,2,1,REC_WORD,666,3 +LTP093,2,1,REC_WORD,1327,8 +LTP093,2,1,REC_WORD,706,5 +LTP093,2,1,REC_WORD,599,6 +LTP093,2,1,REC_WORD,827,9 +LTP093,2,1,REC_WORD,1333,11 +LTP093,2,1,REC_WORD,336,10 +LTP093,2,1,REC_WORD,1349,15 +LTP093,2,1,REC_WORD,746,7 +LTP093,2,1,REC_WORD,408,23 +LTP093,2,1,REC_WORD,339,24 +LTP093,2,1,REC_WORD,999,19 +LTP093,2,1,REC_WORD,283,20 +LTP093,2,2,WORD,1199,1 +LTP093,2,2,WORD,427,2 +LTP093,2,2,WORD,624,3 +LTP093,2,2,WORD,200,4 +LTP093,2,2,WORD,371,5 +LTP093,2,2,WORD,578,6 +LTP093,2,2,WORD,10,7 +LTP093,2,2,WORD,1307,8 +LTP093,2,2,WORD,261,9 +LTP093,2,2,WORD,131,10 +LTP093,2,2,WORD,425,11 +LTP093,2,2,WORD,1555,12 +LTP093,2,2,WORD,641,13 +LTP093,2,2,WORD,53,14 +LTP093,2,2,WORD,1016,15 +LTP093,2,2,WORD,429,16 +LTP093,2,2,WORD,1608,17 +LTP093,2,2,WORD,1172,18 +LTP093,2,2,WORD,839,19 +LTP093,2,2,WORD,771,20 +LTP093,2,2,WORD,308,21 +LTP093,2,2,WORD,1098,22 +LTP093,2,2,WORD,1303,23 +LTP093,2,2,WORD,1232,24 +LTP093,2,2,REC_WORD,429,16 +LTP093,2,2,REC_WORD,1608,17 +LTP093,2,2,REC_WORD,1098,22 +LTP093,2,2,REC_WORD,1303,23 +LTP093,2,2,REC_WORD,131,10 +LTP093,2,2,REC_WORD,425,11 +LTP093,2,2,REC_WORD,1555,12 +LTP093,2,2,REC_WORD,261,9 +LTP093,2,2,REC_WORD,1307,8 +LTP093,2,2,REC_WORD,641,13 +LTP093,2,3,WORD,348,1 +LTP093,2,3,WORD,113,2 +LTP093,2,3,WORD,1002,3 +LTP093,2,3,WORD,849,4 +LTP093,2,3,WORD,490,5 +LTP093,2,3,WORD,846,6 +LTP093,2,3,WORD,499,7 +LTP093,2,3,WORD,602,8 +LTP093,2,3,WORD,1117,9 +LTP093,2,3,WORD,622,10 +LTP093,2,3,WORD,1044,11 +LTP093,2,3,WORD,292,12 +LTP093,2,3,WORD,104,13 +LTP093,2,3,WORD,39,14 +LTP093,2,3,WORD,67,15 +LTP093,2,3,WORD,763,16 +LTP093,2,3,WORD,1451,17 +LTP093,2,3,WORD,833,18 +LTP093,2,3,WORD,1512,19 +LTP093,2,3,WORD,807,20 +LTP093,2,3,WORD,1108,21 +LTP093,2,3,WORD,61,22 +LTP093,2,3,WORD,876,23 +LTP093,2,3,WORD,785,24 +LTP093,2,3,REC_WORD,348,1 +LTP093,2,3,REC_WORD,113,2 +LTP093,2,3,REC_WORD,1002,3 +LTP093,2,3,REC_WORD,849,4 +LTP093,2,3,REC_WORD,490,5 +LTP093,2,3,REC_WORD,846,6 +LTP093,2,3,REC_WORD,602,8 +LTP093,2,3,REC_WORD,1117,9 +LTP093,2,3,REC_WORD,622,10 +LTP093,2,3,REC_WORD,1044,11 +LTP093,2,3,REC_WORD,1108,21 +LTP093,2,3,REC_WORD,39,14 +LTP093,2,3,REC_WORD,833,18 +LTP093,2,4,WORD,1572,1 +LTP093,2,4,WORD,692,2 +LTP093,2,4,WORD,1245,3 +LTP093,2,4,WORD,38,4 +LTP093,2,4,WORD,386,5 +LTP093,2,4,WORD,820,6 +LTP093,2,4,WORD,313,7 +LTP093,2,4,WORD,1123,8 +LTP093,2,4,WORD,766,9 +LTP093,2,4,WORD,299,10 +LTP093,2,4,WORD,1243,11 +LTP093,2,4,WORD,691,12 +LTP093,2,4,WORD,134,13 +LTP093,2,4,WORD,579,14 +LTP093,2,4,WORD,1438,15 +LTP093,2,4,WORD,861,16 +LTP093,2,4,WORD,1629,17 +LTP093,2,4,WORD,1370,18 +LTP093,2,4,WORD,136,19 +LTP093,2,4,WORD,1171,20 +LTP093,2,4,WORD,405,21 +LTP093,2,4,WORD,84,22 +LTP093,2,4,WORD,1148,23 +LTP093,2,4,WORD,417,24 +LTP093,2,4,REC_WORD,405,21 +LTP093,2,4,REC_WORD,84,22 +LTP093,2,4,REC_WORD,1171,20 +LTP093,2,4,REC_WORD,136,19 +LTP093,2,4,REC_WORD,691,12 +LTP093,2,4,REC_WORD,134,13 +LTP093,2,4,REC_WORD,579,14 +LTP093,2,4,REC_WORD,1629,17 +LTP093,2,4,REC_WORD,1370,18 +LTP093,2,4,REC_WORD,1438,15 +LTP093,2,4,REC_WORD,861,16 +LTP093,2,4,REC_WORD,386,5 +LTP093,2,4,REC_WORD,820,6 +LTP093,2,4,REC_WORD,766,9 +LTP093,2,5,WORD,639,1 +LTP093,2,5,WORD,24,2 +LTP093,2,5,WORD,1611,3 +LTP093,2,5,WORD,1532,4 +LTP093,2,5,WORD,972,5 +LTP093,2,5,WORD,633,6 +LTP093,2,5,WORD,248,7 +LTP093,2,5,WORD,790,8 +LTP093,2,5,WORD,699,9 +LTP093,2,5,WORD,501,10 +LTP093,2,5,WORD,929,11 +LTP093,2,5,WORD,1331,12 +LTP093,2,5,WORD,530,13 +LTP093,2,5,WORD,258,14 +LTP093,2,5,WORD,1139,15 +LTP093,2,5,WORD,1626,16 +LTP093,2,5,WORD,982,17 +LTP093,2,5,WORD,570,18 +LTP093,2,5,WORD,497,19 +LTP093,2,5,WORD,754,20 +LTP093,2,5,WORD,1503,21 +LTP093,2,5,WORD,340,22 +LTP093,2,5,WORD,341,23 +LTP093,2,5,WORD,442,24 +LTP093,2,5,REC_WORD,442,24 +LTP093,2,5,REC_WORD,754,20 +LTP093,2,5,REC_WORD,929,11 +LTP093,2,5,REC_WORD,1331,12 +LTP093,2,5,REC_WORD,1139,15 +LTP093,2,5,REC_WORD,1626,16 +LTP093,2,5,REC_WORD,639,1 +LTP093,2,5,REC_WORD,24,2 +LTP093,2,5,REC_WORD,972,5 +LTP093,2,5,REC_WORD,633,6 +LTP093,2,5,REC_WORD,1611,3 +LTP093,2,6,WORD,778,1 +LTP093,2,6,WORD,1176,2 +LTP093,2,6,WORD,670,3 +LTP093,2,6,WORD,1369,4 +LTP093,2,6,WORD,976,5 +LTP093,2,6,WORD,1158,6 +LTP093,2,6,WORD,508,7 +LTP093,2,6,WORD,728,8 +LTP093,2,6,WORD,1143,9 +LTP093,2,6,WORD,1405,10 +LTP093,2,6,WORD,496,11 +LTP093,2,6,WORD,731,12 +LTP093,2,6,WORD,642,13 +LTP093,2,6,WORD,1299,14 +LTP093,2,6,WORD,593,15 +LTP093,2,6,WORD,447,16 +LTP093,2,6,WORD,1414,17 +LTP093,2,6,WORD,682,18 +LTP093,2,6,WORD,372,19 +LTP093,2,6,WORD,1508,20 +LTP093,2,6,WORD,1024,21 +LTP093,2,6,WORD,235,22 +LTP093,2,6,WORD,467,23 +LTP093,2,6,WORD,955,24 +LTP093,2,6,REC_WORD,778,1 +LTP093,2,6,REC_WORD,1176,2 +LTP093,2,6,REC_WORD,670,3 +LTP093,2,6,REC_WORD,1369,4 +LTP093,2,6,REC_WORD,372,19 +LTP093,2,6,REC_WORD,1508,20 +LTP093,2,6,REC_WORD,728,8 +LTP093,2,6,REC_WORD,1299,14 +LTP093,2,6,REC_WORD,593,15 +LTP093,2,6,REC_WORD,976,5 +LTP093,2,6,REC_WORD,1158,6 +LTP093,2,6,REC_WORD,467,23 +LTP093,2,7,WORD,1373,1 +LTP093,2,7,WORD,1022,2 +LTP093,2,7,WORD,708,3 +LTP093,2,7,WORD,1251,4 +LTP093,2,7,WORD,1242,5 +LTP093,2,7,WORD,980,6 +LTP093,2,7,WORD,1132,7 +LTP093,2,7,WORD,1111,8 +LTP093,2,7,WORD,600,9 +LTP093,2,7,WORD,519,10 +LTP093,2,7,WORD,977,11 +LTP093,2,7,WORD,658,12 +LTP093,2,7,WORD,1079,13 +LTP093,2,7,WORD,1238,14 +LTP093,2,7,WORD,908,15 +LTP093,2,7,WORD,1488,16 +LTP093,2,7,WORD,745,17 +LTP093,2,7,WORD,1203,18 +LTP093,2,7,WORD,1544,19 +LTP093,2,7,WORD,1357,20 +LTP093,2,7,WORD,1524,21 +LTP093,2,7,WORD,169,22 +LTP093,2,7,WORD,1423,23 +LTP093,2,7,WORD,1580,24 +LTP093,2,7,REC_WORD,708,3 +LTP093,2,7,REC_WORD,1251,4 +LTP093,2,7,REC_WORD,169,22 +LTP093,2,7,REC_WORD,1423,23 +LTP093,2,7,REC_WORD,1524,21 +LTP093,2,7,REC_WORD,1357,20 +LTP093,2,7,REC_WORD,600,9 +LTP093,2,7,REC_WORD,519,10 +LTP093,2,7,REC_WORD,908,15 +LTP093,2,7,REC_WORD,1488,16 +LTP093,2,7,REC_WORD,745,17 +LTP093,2,7,REC_WORD,1079,13 +LTP093,2,7,REC_WORD,1238,14 +LTP093,2,7,REC_WORD,977,11 +LTP093,2,7,REC_WORD,658,12 +LTP093,2,7,REC_WORD,1373,1 +LTP093,2,8,WORD,794,1 +LTP093,2,8,WORD,63,2 +LTP093,2,8,WORD,1194,3 +LTP093,2,8,WORD,707,4 +LTP093,2,8,WORD,253,5 +LTP093,2,8,WORD,1036,6 +LTP093,2,8,WORD,1341,7 +LTP093,2,8,WORD,885,8 +LTP093,2,8,WORD,1535,9 +LTP093,2,8,WORD,1159,10 +LTP093,2,8,WORD,343,11 +LTP093,2,8,WORD,565,12 +LTP093,2,8,WORD,1011,13 +LTP093,2,8,WORD,724,14 +LTP093,2,8,WORD,323,15 +LTP093,2,8,WORD,325,16 +LTP093,2,8,WORD,1545,17 +LTP093,2,8,WORD,1486,18 +LTP093,2,8,WORD,601,19 +LTP093,2,8,WORD,1256,20 +LTP093,2,8,WORD,760,21 +LTP093,2,8,WORD,1426,22 +LTP093,2,8,WORD,199,23 +LTP093,2,8,WORD,591,24 +LTP093,2,8,REC_WORD,591,24 +LTP093,2,8,REC_WORD,199,23 +LTP093,2,8,REC_WORD,1194,3 +LTP093,2,8,REC_WORD,707,4 +LTP093,2,8,REC_WORD,601,19 +LTP093,2,8,REC_WORD,760,21 +LTP093,2,8,REC_WORD,1426,22 +LTP093,2,8,REC_WORD,1256,20 +LTP093,2,9,WORD,989,1 +LTP093,2,9,WORD,660,2 +LTP093,2,9,WORD,922,3 +LTP093,2,9,WORD,697,4 +LTP093,2,9,WORD,383,5 +LTP093,2,9,WORD,870,6 +LTP093,2,9,WORD,733,7 +LTP093,2,9,WORD,732,8 +LTP093,2,9,WORD,278,9 +LTP093,2,9,WORD,947,10 +LTP093,2,9,WORD,316,11 +LTP093,2,9,WORD,1460,12 +LTP093,2,9,WORD,1049,13 +LTP093,2,9,WORD,937,14 +LTP093,2,9,WORD,592,15 +LTP093,2,9,WORD,776,16 +LTP093,2,9,WORD,485,17 +LTP093,2,9,WORD,1221,18 +LTP093,2,9,WORD,240,19 +LTP093,2,9,WORD,100,20 +LTP093,2,9,WORD,1021,21 +LTP093,2,9,WORD,1280,22 +LTP093,2,9,WORD,960,23 +LTP093,2,9,WORD,1330,24 +LTP093,2,9,REC_WORD,960,23 +LTP093,2,9,REC_WORD,1330,24 +LTP093,2,9,REC_WORD,592,15 +LTP093,2,9,REC_WORD,776,16 +LTP093,2,9,REC_WORD,485,17 +LTP093,2,9,REC_WORD,383,5 +LTP093,2,9,REC_WORD,660,2 +LTP093,2,9,REC_WORD,278,9 +LTP093,2,9,REC_WORD,947,10 +LTP093,2,9,REC_WORD,316,11 +LTP093,2,9,REC_WORD,1460,12 +LTP093,2,10,WORD,866,1 +LTP093,2,10,WORD,795,2 +LTP093,2,10,WORD,1075,3 +LTP093,2,10,WORD,801,4 +LTP093,2,10,WORD,1592,5 +LTP093,2,10,WORD,1505,6 +LTP093,2,10,WORD,987,7 +LTP093,2,10,WORD,1326,8 +LTP093,2,10,WORD,83,9 +LTP093,2,10,WORD,254,10 +LTP093,2,10,WORD,812,11 +LTP093,2,10,WORD,1368,12 +LTP093,2,10,WORD,1071,13 +LTP093,2,10,WORD,718,14 +LTP093,2,10,WORD,1416,15 +LTP093,2,10,WORD,1149,16 +LTP093,2,10,WORD,492,17 +LTP093,2,10,WORD,384,18 +LTP093,2,10,WORD,211,19 +LTP093,2,10,WORD,1197,20 +LTP093,2,10,WORD,1275,21 +LTP093,2,10,WORD,1461,22 +LTP093,2,10,WORD,667,23 +LTP093,2,10,WORD,94,24 +LTP093,2,10,REC_WORD,1416,15 +LTP093,2,10,REC_WORD,1149,16 +LTP093,2,10,REC_WORD,492,17 +LTP093,2,10,REC_WORD,384,18 +LTP093,2,10,REC_WORD,866,1 +LTP093,2,10,REC_WORD,801,4 +LTP093,2,10,REC_WORD,1075,3 +LTP093,2,10,REC_WORD,1592,5 +LTP093,2,10,REC_WORD,1505,6 +LTP093,2,10,REC_WORD,987,7 +LTP093,2,10,REC_WORD,83,9 +LTP093,2,10,REC_WORD,254,10 +LTP093,2,10,REC_WORD,796,-999 +LTP093,2,11,WORD,1581,1 +LTP093,2,11,WORD,994,2 +LTP093,2,11,WORD,66,3 +LTP093,2,11,WORD,1000,4 +LTP093,2,11,WORD,1565,5 +LTP093,2,11,WORD,476,6 +LTP093,2,11,WORD,874,7 +LTP093,2,11,WORD,614,8 +LTP093,2,11,WORD,869,9 +LTP093,2,11,WORD,91,10 +LTP093,2,11,WORD,1385,11 +LTP093,2,11,WORD,1403,12 +LTP093,2,11,WORD,82,13 +LTP093,2,11,WORD,1209,14 +LTP093,2,11,WORD,378,15 +LTP093,2,11,WORD,397,16 +LTP093,2,11,WORD,737,17 +LTP093,2,11,WORD,1113,18 +LTP093,2,11,WORD,400,19 +LTP093,2,11,WORD,1609,20 +LTP093,2,11,WORD,171,21 +LTP093,2,11,WORD,872,22 +LTP093,2,11,WORD,858,23 +LTP093,2,11,WORD,395,24 +LTP093,2,11,REC_WORD,400,19 +LTP093,2,11,REC_WORD,1609,20 +LTP093,2,11,REC_WORD,737,17 +LTP093,2,11,REC_WORD,1113,18 +LTP093,2,11,REC_WORD,171,21 +LTP093,2,11,REC_WORD,872,22 +LTP093,2,11,REC_WORD,858,23 +LTP093,2,11,REC_WORD,395,24 +LTP093,2,11,REC_WORD,1581,1 +LTP093,2,11,REC_WORD,994,2 +LTP093,2,11,REC_WORD,66,3 +LTP093,2,11,REC_WORD,1000,4 +LTP093,2,11,REC_WORD,869,9 +LTP093,2,11,REC_WORD,91,10 +LTP093,2,11,REC_WORD,874,7 +LTP093,2,11,REC_WORD,614,8 +LTP093,2,12,WORD,187,1 +LTP093,2,12,WORD,620,2 +LTP093,2,12,WORD,307,3 +LTP093,2,12,WORD,177,4 +LTP093,2,12,WORD,1587,5 +LTP093,2,12,WORD,33,6 +LTP093,2,12,WORD,1192,7 +LTP093,2,12,WORD,1527,8 +LTP093,2,12,WORD,439,9 +LTP093,2,12,WORD,295,10 +LTP093,2,12,WORD,1329,11 +LTP093,2,12,WORD,1522,12 +LTP093,2,12,WORD,1147,13 +LTP093,2,12,WORD,543,14 +LTP093,2,12,WORD,847,15 +LTP093,2,12,WORD,1301,16 +LTP093,2,12,WORD,437,17 +LTP093,2,12,WORD,689,18 +LTP093,2,12,WORD,541,19 +LTP093,2,12,WORD,1382,20 +LTP093,2,12,WORD,1472,21 +LTP093,2,12,WORD,1261,22 +LTP093,2,12,WORD,1358,23 +LTP093,2,12,WORD,304,24 +LTP093,2,12,REC_WORD,1472,21 +LTP093,2,12,REC_WORD,1261,22 +LTP093,2,12,REC_WORD,1358,23 +LTP093,2,12,REC_WORD,304,24 +LTP093,2,12,REC_WORD,1301,16 +LTP093,2,12,REC_WORD,847,15 +LTP093,2,12,REC_WORD,1192,7 +LTP093,2,12,REC_WORD,1527,8 +LTP093,2,12,REC_WORD,307,3 +LTP093,2,12,REC_WORD,177,4 +LTP093,2,12,REC_WORD,1329,11 +LTP093,2,12,REC_WORD,1522,12 +LTP093,2,12,REC_WORD,1147,13 +LTP093,2,12,REC_WORD,543,14 +LTP093,2,12,REC_WORD,187,1 +LTP093,2,12,REC_WORD,620,2 +LTP093,2,13,WORD,338,1 +LTP093,2,13,WORD,714,2 +LTP093,2,13,WORD,498,3 +LTP093,2,13,WORD,1085,4 +LTP093,2,13,WORD,315,5 +LTP093,2,13,WORD,1347,6 +LTP093,2,13,WORD,916,7 +LTP093,2,13,WORD,1295,8 +LTP093,2,13,WORD,659,9 +LTP093,2,13,WORD,623,10 +LTP093,2,13,WORD,1420,11 +LTP093,2,13,WORD,1456,12 +LTP093,2,13,WORD,198,13 +LTP093,2,13,WORD,210,14 +LTP093,2,13,WORD,804,15 +LTP093,2,13,WORD,142,16 +LTP093,2,13,WORD,1144,17 +LTP093,2,13,WORD,1536,18 +LTP093,2,13,WORD,1048,19 +LTP093,2,13,WORD,255,20 +LTP093,2,13,WORD,1415,21 +LTP093,2,13,WORD,1593,22 +LTP093,2,13,WORD,713,23 +LTP093,2,13,WORD,1215,24 +LTP093,2,13,REC_WORD,1415,21 +LTP093,2,13,REC_WORD,255,20 +LTP093,2,13,REC_WORD,1048,19 +LTP093,2,13,REC_WORD,315,5 +LTP093,2,13,REC_WORD,1347,6 +LTP093,2,13,REC_WORD,1593,22 +LTP093,2,13,REC_WORD,713,23 +LTP093,2,13,REC_WORD,1215,24 +LTP093,2,13,REC_WORD,338,1 +LTP093,2,13,REC_WORD,714,2 +LTP093,2,13,REC_WORD,498,3 +LTP093,2,13,REC_WORD,1085,4 +LTP093,2,14,WORD,1070,1 +LTP093,2,14,WORD,1292,2 +LTP093,2,14,WORD,1384,3 +LTP093,2,14,WORD,1051,4 +LTP093,2,14,WORD,6,5 +LTP093,2,14,WORD,410,6 +LTP093,2,14,WORD,1061,7 +LTP093,2,14,WORD,1224,8 +LTP093,2,14,WORD,157,9 +LTP093,2,14,WORD,166,10 +LTP093,2,14,WORD,13,11 +LTP093,2,14,WORD,1112,12 +LTP093,2,14,WORD,1086,13 +LTP093,2,14,WORD,216,14 +LTP093,2,14,WORD,919,15 +LTP093,2,14,WORD,1351,16 +LTP093,2,14,WORD,184,17 +LTP093,2,14,WORD,963,18 +LTP093,2,14,WORD,1533,19 +LTP093,2,14,WORD,483,20 +LTP093,2,14,WORD,1227,21 +LTP093,2,14,WORD,645,22 +LTP093,2,14,WORD,1411,23 +LTP093,2,14,WORD,407,24 +LTP093,2,14,REC_WORD,1533,19 +LTP093,2,14,REC_WORD,483,20 +LTP093,2,14,REC_WORD,1227,21 +LTP093,2,14,REC_WORD,645,22 +LTP093,2,14,REC_WORD,1292,2 +LTP093,2,14,REC_WORD,6,5 +LTP093,2,14,REC_WORD,1224,8 +LTP093,2,14,REC_WORD,1061,7 +LTP093,2,15,WORD,466,1 +LTP093,2,15,WORD,188,2 +LTP093,2,15,WORD,1633,3 +LTP093,2,15,WORD,1317,4 +LTP093,2,15,WORD,75,5 +LTP093,2,15,WORD,996,6 +LTP093,2,15,WORD,183,7 +LTP093,2,15,WORD,749,8 +LTP093,2,15,WORD,1557,9 +LTP093,2,15,WORD,1202,10 +LTP093,2,15,WORD,265,11 +LTP093,2,15,WORD,1448,12 +LTP093,2,15,WORD,873,13 +LTP093,2,15,WORD,12,14 +LTP093,2,15,WORD,755,15 +LTP093,2,15,WORD,559,16 +LTP093,2,15,WORD,1436,17 +LTP093,2,15,WORD,1047,18 +LTP093,2,15,WORD,719,19 +LTP093,2,15,WORD,675,20 +LTP093,2,15,WORD,1515,21 +LTP093,2,15,WORD,661,22 +LTP093,2,15,WORD,413,23 +LTP093,2,15,WORD,637,24 +LTP093,2,15,REC_WORD,413,23 +LTP093,2,15,REC_WORD,637,24 +LTP093,2,15,REC_WORD,1515,21 +LTP093,2,15,REC_WORD,661,22 +LTP093,2,15,REC_WORD,559,16 +LTP093,2,15,REC_WORD,755,15 +LTP093,2,15,REC_WORD,1436,17 +LTP093,2,15,REC_WORD,1047,18 +LTP093,2,15,REC_WORD,1557,9 +LTP093,2,15,REC_WORD,1202,10 +LTP093,2,15,REC_WORD,873,13 +LTP093,2,15,REC_WORD,12,14 +LTP093,2,15,REC_WORD,183,7 +LTP093,2,15,REC_WORD,749,8 +LTP093,2,15,REC_WORD,996,6 +LTP093,2,15,REC_WORD,75,5 +LTP093,2,16,WORD,829,1 +LTP093,2,16,WORD,1096,2 +LTP093,2,16,WORD,683,3 +LTP093,2,16,WORD,1496,4 +LTP093,2,16,WORD,723,5 +LTP093,2,16,WORD,796,6 +LTP093,2,16,WORD,857,7 +LTP093,2,16,WORD,1140,8 +LTP093,2,16,WORD,995,9 +LTP093,2,16,WORD,159,10 +LTP093,2,16,WORD,1262,11 +LTP093,2,16,WORD,912,12 +LTP093,2,16,WORD,997,13 +LTP093,2,16,WORD,940,14 +LTP093,2,16,WORD,512,15 +LTP093,2,16,WORD,798,16 +LTP093,2,16,WORD,575,17 +LTP093,2,16,WORD,590,18 +LTP093,2,16,WORD,783,19 +LTP093,2,16,WORD,175,20 +LTP093,2,16,WORD,567,21 +LTP093,2,16,WORD,1520,22 +LTP093,2,16,WORD,1092,23 +LTP093,2,16,WORD,598,24 +LTP093,2,16,REC_WORD,1520,22 +LTP093,2,16,REC_WORD,1092,23 +LTP093,2,16,REC_WORD,175,20 +LTP093,2,16,REC_WORD,567,21 +LTP093,2,16,REC_WORD,798,16 +LTP093,2,16,REC_WORD,575,17 +LTP093,2,16,REC_WORD,590,18 +LTP093,2,16,REC_WORD,783,19 +LTP093,2,16,REC_WORD,1096,2 +LTP093,2,16,REC_WORD,829,1 +LTP093,2,16,REC_WORD,912,12 +LTP093,2,16,REC_WORD,997,13 +LTP093,2,16,REC_WORD,683,3 +LTP093,2,16,REC_WORD,1496,4 +LTP093,2,16,REC_WORD,796,6 +LTP093,2,16,REC_WORD,857,7 +LTP093,2,16,REC_WORD,1140,8 +LTP093,2,16,REC_WORD,995,9 +LTP093,2,16,REC_WORD,159,10 +LTP093,2,17,WORD,635,1 +LTP093,2,17,WORD,446,2 +LTP093,2,17,WORD,605,3 +LTP093,2,17,WORD,900,4 +LTP093,2,17,WORD,573,5 +LTP093,2,17,WORD,734,6 +LTP093,2,17,WORD,1511,7 +LTP093,2,17,WORD,139,8 +LTP093,2,17,WORD,1287,9 +LTP093,2,17,WORD,1501,10 +LTP093,2,17,WORD,1271,11 +LTP093,2,17,WORD,388,12 +LTP093,2,17,WORD,782,13 +LTP093,2,17,WORD,752,14 +LTP093,2,17,WORD,441,15 +LTP093,2,17,WORD,328,16 +LTP093,2,17,WORD,1293,17 +LTP093,2,17,WORD,800,18 +LTP093,2,17,WORD,1605,19 +LTP093,2,17,WORD,1272,20 +LTP093,2,17,WORD,64,21 +LTP093,2,17,WORD,1345,22 +LTP093,2,17,WORD,959,23 +LTP093,2,17,WORD,1027,24 +LTP093,2,17,REC_WORD,64,21 +LTP093,2,17,REC_WORD,1345,22 +LTP093,2,17,REC_WORD,959,23 +LTP093,2,17,REC_WORD,-1,-999 +LTP093,2,17,REC_WORD,1027,24 +LTP093,2,17,REC_WORD,388,12 +LTP093,2,17,REC_WORD,1293,17 +LTP093,2,17,REC_WORD,752,14 +LTP093,2,17,REC_WORD,635,1 +LTP093,2,17,REC_WORD,446,2 +LTP093,2,17,REC_WORD,605,3 +LTP093,2,17,REC_WORD,900,4 +LTP093,2,17,REC_WORD,734,6 +LTP093,2,17,REC_WORD,573,5 +LTP093,2,17,REC_WORD,1511,7 +LTP093,2,17,REC_WORD,139,8 +LTP093,2,18,WORD,1200,1 +LTP093,2,18,WORD,852,2 +LTP093,2,18,WORD,1173,3 +LTP093,2,18,WORD,68,4 +LTP093,2,18,WORD,1124,5 +LTP093,2,18,WORD,1356,6 +LTP093,2,18,WORD,1521,7 +LTP093,2,18,WORD,194,8 +LTP093,2,18,WORD,901,9 +LTP093,2,18,WORD,618,10 +LTP093,2,18,WORD,55,11 +LTP093,2,18,WORD,1493,12 +LTP093,2,18,WORD,553,13 +LTP093,2,18,WORD,164,14 +LTP093,2,18,WORD,1095,15 +LTP093,2,18,WORD,1076,16 +LTP093,2,18,WORD,1229,17 +LTP093,2,18,WORD,145,18 +LTP093,2,18,WORD,1006,19 +LTP093,2,18,WORD,1519,20 +LTP093,2,18,WORD,726,21 +LTP093,2,18,WORD,203,22 +LTP093,2,18,WORD,1060,23 +LTP093,2,18,WORD,584,24 +LTP093,2,18,REC_WORD,726,21 +LTP093,2,18,REC_WORD,203,22 +LTP093,2,18,REC_WORD,584,24 +LTP093,2,18,REC_WORD,1060,23 +LTP093,2,18,REC_WORD,553,13 +LTP093,2,18,REC_WORD,1493,12 +LTP093,2,18,REC_WORD,1076,16 +LTP093,2,18,REC_WORD,1521,7 +LTP093,2,18,REC_WORD,194,8 +LTP093,2,18,REC_WORD,901,9 +LTP093,2,18,REC_WORD,618,10 +LTP093,2,18,REC_WORD,1124,5 +LTP093,2,18,REC_WORD,1356,6 +LTP093,2,18,REC_WORD,1200,1 +LTP093,2,18,REC_WORD,852,2 +LTP093,2,18,REC_WORD,68,4 +LTP093,2,18,REC_WORD,1173,3 +LTP093,2,19,WORD,1057,1 +LTP093,2,19,WORD,1407,2 +LTP093,2,19,WORD,1031,3 +LTP093,2,19,WORD,654,4 +LTP093,2,19,WORD,488,5 +LTP093,2,19,WORD,1312,6 +LTP093,2,19,WORD,1374,7 +LTP093,2,19,WORD,1219,8 +LTP093,2,19,WORD,1440,9 +LTP093,2,19,WORD,133,10 +LTP093,2,19,WORD,137,11 +LTP093,2,19,WORD,1017,12 +LTP093,2,19,WORD,162,13 +LTP093,2,19,WORD,1284,14 +LTP093,2,19,WORD,606,15 +LTP093,2,19,WORD,179,16 +LTP093,2,19,WORD,1400,17 +LTP093,2,19,WORD,389,18 +LTP093,2,19,WORD,764,19 +LTP093,2,19,WORD,1319,20 +LTP093,2,19,WORD,1088,21 +LTP093,2,19,WORD,871,22 +LTP093,2,19,WORD,792,23 +LTP093,2,19,WORD,1427,24 +LTP093,2,19,REC_WORD,871,22 +LTP093,2,19,REC_WORD,792,23 +LTP093,2,19,REC_WORD,1319,20 +LTP093,2,19,REC_WORD,488,5 +LTP093,2,19,REC_WORD,1312,6 +LTP093,2,19,REC_WORD,1374,7 +LTP093,2,19,REC_WORD,1219,8 +LTP093,2,19,REC_WORD,1440,9 +LTP093,2,19,REC_WORD,133,10 +LTP093,2,19,REC_WORD,179,16 +LTP093,2,19,REC_WORD,1284,14 +LTP093,2,19,REC_WORD,162,13 +LTP093,2,20,WORD,1422,1 +LTP093,2,20,WORD,1258,2 +LTP093,2,20,WORD,494,3 +LTP093,2,20,WORD,888,4 +LTP093,2,20,WORD,1392,5 +LTP093,2,20,WORD,1065,6 +LTP093,2,20,WORD,1015,7 +LTP093,2,20,WORD,1037,8 +LTP093,2,20,WORD,1013,9 +LTP093,2,20,WORD,1093,10 +LTP093,2,20,WORD,1636,11 +LTP093,2,20,WORD,883,12 +LTP093,2,20,WORD,29,13 +LTP093,2,20,WORD,738,14 +LTP093,2,20,WORD,1119,15 +LTP093,2,20,WORD,109,16 +LTP093,2,20,WORD,1562,17 +LTP093,2,20,WORD,1478,18 +LTP093,2,20,WORD,125,19 +LTP093,2,20,WORD,628,20 +LTP093,2,20,WORD,702,21 +LTP093,2,20,WORD,1087,22 +LTP093,2,20,WORD,809,23 +LTP093,2,20,WORD,769,24 +LTP093,2,20,REC_WORD,1015,7 +LTP093,2,20,REC_WORD,1037,8 +LTP093,2,20,REC_WORD,1013,9 +LTP093,2,20,REC_WORD,1093,10 +LTP093,2,20,REC_WORD,1119,15 +LTP093,2,20,REC_WORD,1562,17 +LTP093,2,20,REC_WORD,1478,18 +LTP093,2,20,REC_WORD,109,16 +LTP093,2,20,REC_WORD,125,19 +LTP093,2,20,REC_WORD,702,21 +LTP093,2,20,REC_WORD,1087,22 +LTP093,2,20,REC_WORD,809,23 +LTP093,2,21,WORD,520,1 +LTP093,2,21,WORD,932,2 +LTP093,2,21,WORD,1089,3 +LTP093,2,21,WORD,1526,4 +LTP093,2,21,WORD,1315,5 +LTP093,2,21,WORD,1371,6 +LTP093,2,21,WORD,604,7 +LTP093,2,21,WORD,627,8 +LTP093,2,21,WORD,358,9 +LTP093,2,21,WORD,435,10 +LTP093,2,21,WORD,431,11 +LTP093,2,21,WORD,1530,12 +LTP093,2,21,WORD,1628,13 +LTP093,2,21,WORD,696,14 +LTP093,2,21,WORD,793,15 +LTP093,2,21,WORD,267,16 +LTP093,2,21,WORD,119,17 +LTP093,2,21,WORD,546,18 +LTP093,2,21,WORD,1019,19 +LTP093,2,21,WORD,840,20 +LTP093,2,21,WORD,821,21 +LTP093,2,21,WORD,415,22 +LTP093,2,21,WORD,1125,23 +LTP093,2,21,WORD,392,24 +LTP093,2,21,REC_WORD,821,21 +LTP093,2,21,REC_WORD,415,22 +LTP093,2,21,REC_WORD,1125,23 +LTP093,2,21,REC_WORD,392,24 +LTP093,2,21,REC_WORD,604,7 +LTP093,2,21,REC_WORD,627,8 +LTP093,2,21,REC_WORD,1530,12 +LTP093,2,21,REC_WORD,431,11 +LTP093,2,21,REC_WORD,932,2 +LTP093,2,21,REC_WORD,520,1 +LTP093,2,21,REC_WORD,1089,3 +LTP093,2,21,REC_WORD,1526,4 +LTP093,2,22,WORD,1621,1 +LTP093,2,22,WORD,953,2 +LTP093,2,22,WORD,879,3 +LTP093,2,22,WORD,1395,4 +LTP093,2,22,WORD,1620,5 +LTP093,2,22,WORD,1282,6 +LTP093,2,22,WORD,1622,7 +LTP093,2,22,WORD,715,8 +LTP093,2,22,WORD,327,9 +LTP093,2,22,WORD,1246,10 +LTP093,2,22,WORD,1184,11 +LTP093,2,22,WORD,168,12 +LTP093,2,22,WORD,848,13 +LTP093,2,22,WORD,1388,14 +LTP093,2,22,WORD,895,15 +LTP093,2,22,WORD,1250,16 +LTP093,2,22,WORD,1009,17 +LTP093,2,22,WORD,1618,18 +LTP093,2,22,WORD,1332,19 +LTP093,2,22,WORD,1546,20 +LTP093,2,22,WORD,35,21 +LTP093,2,22,WORD,988,22 +LTP093,2,22,WORD,368,23 +LTP093,2,22,WORD,108,24 +LTP093,2,22,REC_WORD,1250,16 +LTP093,2,22,REC_WORD,1009,17 +LTP093,2,22,REC_WORD,1621,1 +LTP093,2,22,REC_WORD,953,2 +LTP093,2,22,REC_WORD,1395,4 +LTP093,2,22,REC_WORD,879,3 +LTP093,2,22,REC_WORD,1620,5 +LTP093,2,22,REC_WORD,1282,6 +LTP093,2,22,REC_WORD,1282,6 +LTP093,2,22,REC_WORD,715,8 +LTP093,2,22,REC_WORD,108,24 +LTP093,2,22,REC_WORD,848,13 +LTP093,2,22,REC_WORD,168,12 +LTP093,2,23,WORD,127,1 +LTP093,2,23,WORD,1170,2 +LTP093,2,23,WORD,1635,3 +LTP093,2,23,WORD,403,4 +LTP093,2,23,WORD,580,5 +LTP093,2,23,WORD,1155,6 +LTP093,2,23,WORD,974,7 +LTP093,2,23,WORD,1468,8 +LTP093,2,23,WORD,1606,9 +LTP093,2,23,WORD,484,10 +LTP093,2,23,WORD,834,11 +LTP093,2,23,WORD,662,12 +LTP093,2,23,WORD,1152,13 +LTP093,2,23,WORD,1343,14 +LTP093,2,23,WORD,1183,15 +LTP093,2,23,WORD,1625,16 +LTP093,2,23,WORD,88,17 +LTP093,2,23,WORD,684,18 +LTP093,2,23,WORD,373,19 +LTP093,2,23,WORD,86,20 +LTP093,2,23,WORD,1032,21 +LTP093,2,23,WORD,1104,22 +LTP093,2,23,WORD,143,23 +LTP093,2,23,WORD,1578,24 +LTP093,2,23,REC_WORD,834,11 +LTP093,2,23,REC_WORD,86,20 +LTP093,2,23,REC_WORD,1032,21 +LTP093,2,23,REC_WORD,662,12 +LTP093,2,23,REC_WORD,1152,13 +LTP093,2,23,REC_WORD,1104,22 +LTP093,2,23,REC_WORD,143,23 +LTP093,2,23,REC_WORD,1578,24 +LTP093,2,24,WORD,172,1 +LTP093,2,24,WORD,280,2 +LTP093,2,24,WORD,353,3 +LTP093,2,24,WORD,1631,4 +LTP093,2,24,WORD,495,5 +LTP093,2,24,WORD,1260,6 +LTP093,2,24,WORD,814,7 +LTP093,2,24,WORD,1066,8 +LTP093,2,24,WORD,843,9 +LTP093,2,24,WORD,390,10 +LTP093,2,24,WORD,346,11 +LTP093,2,24,WORD,935,12 +LTP093,2,24,WORD,401,13 +LTP093,2,24,WORD,1080,14 +LTP093,2,24,WORD,761,15 +LTP093,2,24,WORD,223,16 +LTP093,2,24,WORD,561,17 +LTP093,2,24,WORD,46,18 +LTP093,2,24,WORD,1035,19 +LTP093,2,24,WORD,878,20 +LTP093,2,24,WORD,569,21 +LTP093,2,24,WORD,1294,22 +LTP093,2,24,WORD,5,23 +LTP093,2,24,WORD,1328,24 +LTP093,2,24,REC_WORD,561,17 +LTP093,2,24,REC_WORD,46,18 +LTP093,2,24,REC_WORD,569,21 +LTP093,2,24,REC_WORD,1294,22 +LTP093,2,24,REC_WORD,1328,24 +LTP093,2,24,REC_WORD,5,23 +LTP093,2,24,REC_WORD,172,1 +LTP093,2,24,REC_WORD,280,2 +LTP093,2,24,REC_WORD,1631,4 +LTP093,3,1,WORD,764,1 +LTP093,3,1,WORD,1293,2 +LTP093,3,1,WORD,1408,3 +LTP093,3,1,WORD,203,4 +LTP093,3,1,WORD,1092,5 +LTP093,3,1,WORD,569,6 +LTP093,3,1,WORD,1426,7 +LTP093,3,1,WORD,136,8 +LTP093,3,1,WORD,1400,9 +LTP093,3,1,WORD,1140,10 +LTP093,3,1,WORD,660,11 +LTP093,3,1,WORD,389,12 +LTP093,3,1,WORD,441,13 +LTP093,3,1,WORD,1557,14 +LTP093,3,1,WORD,446,15 +LTP093,3,1,WORD,1621,16 +LTP093,3,1,WORD,304,17 +LTP093,3,1,WORD,800,18 +LTP093,3,1,WORD,323,19 +LTP093,3,1,WORD,1405,20 +LTP093,3,1,WORD,553,21 +LTP093,3,1,WORD,1319,22 +LTP093,3,1,WORD,1080,23 +LTP093,3,1,WORD,707,24 +LTP093,3,1,REC_WORD,764,1 +LTP093,3,1,REC_WORD,1293,2 +LTP093,3,1,REC_WORD,1092,5 +LTP093,3,1,REC_WORD,569,6 +LTP093,3,1,REC_WORD,304,17 +LTP093,3,1,REC_WORD,800,18 +LTP093,3,1,REC_WORD,323,19 +LTP093,3,1,REC_WORD,1405,20 +LTP093,3,1,REC_WORD,553,21 +LTP093,3,1,REC_WORD,1319,22 +LTP093,3,1,REC_WORD,1080,23 +LTP093,3,1,REC_WORD,707,24 +LTP093,3,1,REC_WORD,1557,14 +LTP093,3,2,WORD,1605,1 +LTP093,3,2,WORD,1358,2 +LTP093,3,2,WORD,1371,3 +LTP093,3,2,WORD,223,4 +LTP093,3,2,WORD,1024,5 +LTP093,3,2,WORD,895,6 +LTP093,3,2,WORD,1493,7 +LTP093,3,2,WORD,974,8 +LTP093,3,2,WORD,501,9 +LTP093,3,2,WORD,610,10 +LTP093,3,2,WORD,697,11 +LTP093,3,2,WORD,1036,12 +LTP093,3,2,WORD,125,13 +LTP093,3,2,WORD,198,14 +LTP093,3,2,WORD,280,15 +LTP093,3,2,WORD,1544,16 +LTP093,3,2,WORD,812,17 +LTP093,3,2,WORD,995,18 +LTP093,3,2,WORD,1242,19 +LTP093,3,2,WORD,336,20 +LTP093,3,2,WORD,691,21 +LTP093,3,2,WORD,1486,22 +LTP093,3,2,WORD,308,23 +LTP093,3,2,WORD,732,24 +LTP093,3,2,REC_WORD,280,15 +LTP093,3,2,REC_WORD,1544,16 +LTP093,3,2,REC_WORD,995,18 +LTP093,3,2,REC_WORD,812,17 +LTP093,3,2,REC_WORD,1605,1 +LTP093,3,2,REC_WORD,1358,2 +LTP093,3,3,WORD,1505,1 +LTP093,3,3,WORD,988,2 +LTP093,3,3,WORD,590,3 +LTP093,3,3,WORD,628,4 +LTP093,3,3,WORD,1262,5 +LTP093,3,3,WORD,1260,6 +LTP093,3,3,WORD,1000,7 +LTP093,3,3,WORD,1159,8 +LTP093,3,3,WORD,814,9 +LTP093,3,3,WORD,874,10 +LTP093,3,3,WORD,1436,11 +LTP093,3,3,WORD,403,12 +LTP093,3,3,WORD,726,13 +LTP093,3,3,WORD,1022,14 +LTP093,3,3,WORD,371,15 +LTP093,3,3,WORD,989,16 +LTP093,3,3,WORD,1587,17 +LTP093,3,3,WORD,737,18 +LTP093,3,3,WORD,959,19 +LTP093,3,3,WORD,833,20 +LTP093,3,3,WORD,1315,21 +LTP093,3,3,WORD,683,22 +LTP093,3,3,WORD,1581,23 +LTP093,3,3,WORD,1224,24 +LTP093,3,3,REC_WORD,1315,21 +LTP093,3,3,REC_WORD,683,22 +LTP093,3,3,REC_WORD,1581,23 +LTP093,3,3,REC_WORD,1224,24 +LTP093,3,3,REC_WORD,814,9 +LTP093,3,3,REC_WORD,628,4 +LTP093,3,3,REC_WORD,590,3 +LTP093,3,3,REC_WORD,1505,1 +LTP093,3,3,REC_WORD,988,2 +LTP093,3,4,WORD,1203,1 +LTP093,3,4,WORD,1144,2 +LTP093,3,4,WORD,1215,3 +LTP093,3,4,WORD,1172,4 +LTP093,3,4,WORD,1015,5 +LTP093,3,4,WORD,83,6 +LTP093,3,4,WORD,109,7 +LTP093,3,4,WORD,1200,8 +LTP093,3,4,WORD,637,9 +LTP093,3,4,WORD,1440,10 +LTP093,3,4,WORD,879,11 +LTP093,3,4,WORD,776,12 +LTP093,3,4,WORD,1496,13 +LTP093,3,4,WORD,1139,14 +LTP093,3,4,WORD,1572,15 +LTP093,3,4,WORD,1355,16 +LTP093,3,4,WORD,199,17 +LTP093,3,4,WORD,1618,18 +LTP093,3,4,WORD,210,19 +LTP093,3,4,WORD,714,20 +LTP093,3,4,WORD,1526,21 +LTP093,3,4,WORD,1625,22 +LTP093,3,4,WORD,761,23 +LTP093,3,4,WORD,682,24 +LTP093,3,4,REC_WORD,1526,21 +LTP093,3,4,REC_WORD,1625,22 +LTP093,3,4,REC_WORD,761,23 +LTP093,3,4,REC_WORD,682,24 +LTP093,3,4,REC_WORD,210,19 +LTP093,3,4,REC_WORD,714,20 +LTP093,3,4,REC_WORD,1203,1 +LTP093,3,4,REC_WORD,199,17 +LTP093,3,4,REC_WORD,1618,18 +LTP093,3,4,REC_WORD,637,9 +LTP093,3,4,REC_WORD,1440,10 +LTP093,3,5,WORD,1124,1 +LTP093,3,5,WORD,706,2 +LTP093,3,5,WORD,1031,3 +LTP093,3,5,WORD,888,4 +LTP093,3,5,WORD,675,5 +LTP093,3,5,WORD,492,6 +LTP093,3,5,WORD,584,7 +LTP093,3,5,WORD,341,8 +LTP093,3,5,WORD,847,9 +LTP093,3,5,WORD,1009,10 +LTP093,3,5,WORD,1147,11 +LTP093,3,5,WORD,1631,12 +LTP093,3,5,WORD,1411,13 +LTP093,3,5,WORD,1070,14 +LTP093,3,5,WORD,240,15 +LTP093,3,5,WORD,749,16 +LTP093,3,5,WORD,388,17 +LTP093,3,5,WORD,13,18 +LTP093,3,5,WORD,661,19 +LTP093,3,5,WORD,88,20 +LTP093,3,5,WORD,1368,21 +LTP093,3,5,WORD,883,22 +LTP093,3,5,WORD,599,23 +LTP093,3,5,WORD,977,24 +LTP093,3,5,REC_WORD,661,19 +LTP093,3,5,REC_WORD,88,20 +LTP093,3,5,REC_WORD,1368,21 +LTP093,3,5,REC_WORD,883,22 +LTP093,3,5,REC_WORD,977,24 +LTP093,3,5,REC_WORD,599,23 +LTP093,3,5,REC_WORD,1124,1 +LTP093,3,5,REC_WORD,706,2 +LTP093,3,5,REC_WORD,1031,3 +LTP093,3,5,REC_WORD,888,4 +LTP093,3,5,REC_WORD,675,5 +LTP093,3,5,REC_WORD,492,6 +LTP093,3,5,REC_WORD,584,7 +LTP093,3,5,REC_WORD,341,8 +LTP093,3,5,REC_WORD,1147,11 +LTP093,3,6,WORD,235,1 +LTP093,3,6,WORD,1016,2 +LTP093,3,6,WORD,1292,3 +LTP093,3,6,WORD,33,4 +LTP093,3,6,WORD,1176,5 +LTP093,3,6,WORD,1117,6 +LTP093,3,6,WORD,64,7 +LTP093,3,6,WORD,1261,8 +LTP093,3,6,WORD,752,9 +LTP093,3,6,WORD,1197,10 +LTP093,3,6,WORD,1415,11 +LTP093,3,6,WORD,1282,12 +LTP093,3,6,WORD,585,13 +LTP093,3,6,WORD,783,14 +LTP093,3,6,WORD,937,15 +LTP093,3,6,WORD,1524,16 +LTP093,3,6,WORD,829,17 +LTP093,3,6,WORD,1044,18 +LTP093,3,6,WORD,316,19 +LTP093,3,6,WORD,1407,20 +LTP093,3,6,WORD,1369,21 +LTP093,3,6,WORD,620,22 +LTP093,3,6,WORD,495,23 +LTP093,3,6,WORD,1250,24 +LTP093,3,6,REC_WORD,1415,11 +LTP093,3,6,REC_WORD,1415,11 +LTP093,3,6,REC_WORD,752,9 +LTP093,3,6,REC_WORD,1197,10 +LTP093,3,6,REC_WORD,235,1 +LTP093,3,6,REC_WORD,1016,2 +LTP093,3,6,REC_WORD,33,4 +LTP093,3,6,REC_WORD,1292,3 +LTP093,3,6,REC_WORD,1176,5 +LTP093,3,6,REC_WORD,1117,6 +LTP093,3,6,REC_WORD,64,7 +LTP093,3,6,REC_WORD,1261,8 +LTP093,3,7,WORD,343,1 +LTP093,3,7,WORD,932,2 +LTP093,3,7,WORD,1593,3 +LTP093,3,7,WORD,633,4 +LTP093,3,7,WORD,1104,5 +LTP093,3,7,WORD,1520,6 +LTP093,3,7,WORD,1194,7 +LTP093,3,7,WORD,796,8 +LTP093,3,7,WORD,498,9 +LTP093,3,7,WORD,267,10 +LTP093,3,7,WORD,410,11 +LTP093,3,7,WORD,1343,12 +LTP093,3,7,WORD,1155,13 +LTP093,3,7,WORD,666,14 +LTP093,3,7,WORD,1345,15 +LTP093,3,7,WORD,104,16 +LTP093,3,7,WORD,1307,17 +LTP093,3,7,WORD,667,18 +LTP093,3,7,WORD,1521,19 +LTP093,3,7,WORD,1546,20 +LTP093,3,7,WORD,415,21 +LTP093,3,7,WORD,417,22 +LTP093,3,7,WORD,849,23 +LTP093,3,7,WORD,1519,24 +LTP093,3,7,REC_WORD,932,2 +LTP093,3,7,REC_WORD,343,1 +LTP093,3,7,REC_WORD,666,14 +LTP093,3,7,REC_WORD,1345,15 +LTP093,3,7,REC_WORD,1104,5 +LTP093,3,7,REC_WORD,1520,6 +LTP093,3,7,REC_WORD,104,16 +LTP093,3,7,REC_WORD,1307,17 +LTP093,3,7,REC_WORD,633,4 +LTP093,3,8,WORD,184,1 +LTP093,3,8,WORD,1095,2 +LTP093,3,8,WORD,1287,3 +LTP093,3,8,WORD,1532,4 +LTP093,3,8,WORD,68,5 +LTP093,3,8,WORD,1609,6 +LTP093,3,8,WORD,1633,7 +LTP093,3,8,WORD,1209,8 +LTP093,3,8,WORD,795,9 +LTP093,3,8,WORD,876,10 +LTP093,3,8,WORD,1098,11 +LTP093,3,8,WORD,1312,12 +LTP093,3,8,WORD,1232,13 +LTP093,3,8,WORD,1326,14 +LTP093,3,8,WORD,1112,15 +LTP093,3,8,WORD,601,16 +LTP093,3,8,WORD,1170,17 +LTP093,3,8,WORD,1183,18 +LTP093,3,8,WORD,771,19 +LTP093,3,8,WORD,885,20 +LTP093,3,8,WORD,1333,21 +LTP093,3,8,WORD,1301,22 +LTP093,3,8,WORD,580,23 +LTP093,3,8,WORD,476,24 +LTP093,3,8,REC_WORD,580,23 +LTP093,3,8,REC_WORD,476,24 +LTP093,3,8,REC_WORD,1170,17 +LTP093,3,8,REC_WORD,1183,18 +LTP093,3,8,REC_WORD,771,19 +LTP093,3,8,REC_WORD,885,20 +LTP093,3,8,REC_WORD,1609,6 +LTP093,3,8,REC_WORD,68,5 +LTP093,3,8,REC_WORD,1098,11 +LTP093,3,8,REC_WORD,1312,12 +LTP093,3,8,REC_WORD,1301,22 +LTP093,3,8,REC_WORD,1232,13 +LTP093,3,8,REC_WORD,1326,14 +LTP093,3,8,REC_WORD,601,16 +LTP093,3,8,REC_WORD,1112,15 +LTP093,3,9,WORD,953,1 +LTP093,3,9,WORD,183,2 +LTP093,3,9,WORD,346,3 +LTP093,3,9,WORD,827,4 +LTP093,3,9,WORD,383,5 +LTP093,3,9,WORD,866,6 +LTP093,3,9,WORD,137,7 +LTP093,3,9,WORD,166,8 +LTP093,3,9,WORD,226,9 +LTP093,3,9,WORD,901,10 +LTP093,3,9,WORD,1530,11 +LTP093,3,9,WORD,1451,12 +LTP093,3,9,WORD,327,13 +LTP093,3,9,WORD,598,14 +LTP093,3,9,WORD,338,15 +LTP093,3,9,WORD,38,16 +LTP093,3,9,WORD,996,17 +LTP093,3,9,WORD,1622,18 +LTP093,3,9,WORD,719,19 +LTP093,3,9,WORD,1158,20 +LTP093,3,9,WORD,1327,21 +LTP093,3,9,WORD,1280,22 +LTP093,3,9,WORD,840,23 +LTP093,3,9,WORD,893,24 +LTP093,3,9,REC_WORD,1622,18 +LTP093,3,9,REC_WORD,719,19 +LTP093,3,9,REC_WORD,1158,20 +LTP093,3,9,REC_WORD,1327,21 +LTP093,3,9,REC_WORD,996,17 +LTP093,3,9,REC_WORD,38,16 +LTP093,3,9,REC_WORD,953,1 +LTP093,3,9,REC_WORD,183,2 +LTP093,3,9,REC_WORD,346,3 +LTP093,3,9,REC_WORD,827,4 +LTP093,3,9,REC_WORD,383,5 +LTP093,3,9,REC_WORD,901,10 +LTP093,3,9,REC_WORD,1530,11 +LTP093,3,9,REC_WORD,1451,12 +LTP093,3,9,REC_WORD,226,9 +LTP093,3,9,REC_WORD,166,8 +LTP093,3,10,WORD,1275,1 +LTP093,3,10,WORD,715,2 +LTP093,3,10,WORD,10,3 +LTP093,3,10,WORD,1027,4 +LTP093,3,10,WORD,1328,5 +LTP093,3,10,WORD,1478,6 +LTP093,3,10,WORD,108,7 +LTP093,3,10,WORD,1202,8 +LTP093,3,10,WORD,1011,9 +LTP093,3,10,WORD,723,10 +LTP093,3,10,WORD,1294,11 +LTP093,3,10,WORD,670,12 +LTP093,3,10,WORD,900,13 +LTP093,3,10,WORD,622,14 +LTP093,3,10,WORD,1356,15 +LTP093,3,10,WORD,86,16 +LTP093,3,10,WORD,935,17 +LTP093,3,10,WORD,131,18 +LTP093,3,10,WORD,955,19 +LTP093,3,10,WORD,1427,20 +LTP093,3,10,WORD,794,21 +LTP093,3,10,WORD,922,22 +LTP093,3,10,WORD,1057,23 +LTP093,3,10,WORD,623,24 +LTP093,3,10,REC_WORD,1356,15 +LTP093,3,10,REC_WORD,86,16 +LTP093,3,10,REC_WORD,935,17 +LTP093,3,10,REC_WORD,131,18 +LTP093,3,10,REC_WORD,794,21 +LTP093,3,10,REC_WORD,922,22 +LTP093,3,10,REC_WORD,623,24 +LTP093,3,11,WORD,766,1 +LTP093,3,11,WORD,798,2 +LTP093,3,11,WORD,604,3 +LTP093,3,11,WORD,258,4 +LTP093,3,11,WORD,1284,5 +LTP093,3,11,WORD,171,6 +LTP093,3,11,WORD,567,7 +LTP093,3,11,WORD,1382,8 +LTP093,3,11,WORD,358,9 +LTP093,3,11,WORD,328,10 +LTP093,3,11,WORD,731,11 +LTP093,3,11,WORD,1221,12 +LTP093,3,11,WORD,200,13 +LTP093,3,11,WORD,1456,14 +LTP093,3,11,WORD,1219,15 +LTP093,3,11,WORD,1123,16 +LTP093,3,11,WORD,724,17 +LTP093,3,11,WORD,642,18 +LTP093,3,11,WORD,618,19 +LTP093,3,11,WORD,1420,20 +LTP093,3,11,WORD,175,21 +LTP093,3,11,WORD,940,22 +LTP093,3,11,WORD,591,23 +LTP093,3,11,WORD,1535,24 +LTP093,3,11,REC_WORD,642,18 +LTP093,3,11,REC_WORD,618,19 +LTP093,3,11,REC_WORD,1420,20 +LTP093,3,11,REC_WORD,175,21 +LTP093,3,11,REC_WORD,171,6 +LTP093,3,11,REC_WORD,604,3 +LTP093,3,11,REC_WORD,328,10 +LTP093,3,12,WORD,561,1 +LTP093,3,12,WORD,689,2 +LTP093,3,12,WORD,497,3 +LTP093,3,12,WORD,520,4 +LTP093,3,12,WORD,1545,5 +LTP093,3,12,WORD,29,6 +LTP093,3,12,WORD,769,7 +LTP093,3,12,WORD,1096,8 +LTP093,3,12,WORD,1199,9 +LTP093,3,12,WORD,1245,10 +LTP093,3,12,WORD,172,11 +LTP093,3,12,WORD,912,12 +LTP093,3,12,WORD,746,13 +LTP093,3,12,WORD,278,14 +LTP093,3,12,WORD,1611,15 +LTP093,3,12,WORD,407,16 +LTP093,3,12,WORD,1251,17 +LTP093,3,12,WORD,858,18 +LTP093,3,12,WORD,821,19 +LTP093,3,12,WORD,1395,20 +LTP093,3,12,WORD,1051,21 +LTP093,3,12,WORD,696,22 +LTP093,3,12,WORD,592,23 +LTP093,3,12,WORD,801,24 +LTP093,3,12,REC_WORD,696,22 +LTP093,3,12,REC_WORD,592,23 +LTP093,3,12,REC_WORD,520,4 +LTP093,3,12,REC_WORD,497,3 +LTP093,3,12,REC_WORD,1096,8 +LTP093,3,12,REC_WORD,1199,9 +LTP093,3,12,REC_WORD,407,16 +LTP093,3,12,REC_WORD,1251,17 +LTP093,3,12,REC_WORD,858,18 +LTP093,3,12,REC_WORD,821,19 +LTP093,3,12,REC_WORD,912,12 +LTP093,3,12,REC_WORD,746,13 +LTP093,3,12,REC_WORD,278,14 +LTP093,3,12,REC_WORD,1611,15 +LTP093,3,13,WORD,1562,1 +LTP093,3,13,WORD,1347,2 +LTP093,3,13,WORD,754,3 +LTP093,3,13,WORD,429,4 +LTP093,3,13,WORD,67,5 +LTP093,3,13,WORD,1580,6 +LTP093,3,13,WORD,871,7 +LTP093,3,13,WORD,755,8 +LTP093,3,13,WORD,1460,9 +LTP093,3,13,WORD,1626,10 +LTP093,3,13,WORD,24,11 +LTP093,3,13,WORD,1085,12 +LTP093,3,13,WORD,1527,13 +LTP093,3,13,WORD,187,14 +LTP093,3,13,WORD,976,15 +LTP093,3,13,WORD,606,16 +LTP093,3,13,WORD,1303,17 +LTP093,3,13,WORD,573,18 +LTP093,3,13,WORD,1048,19 +LTP093,3,13,WORD,254,20 +LTP093,3,13,WORD,339,21 +LTP093,3,13,WORD,565,22 +LTP093,3,13,WORD,1021,23 +LTP093,3,13,WORD,627,24 +LTP093,3,13,REC_WORD,1021,23 +LTP093,3,13,REC_WORD,627,24 +LTP093,3,13,REC_WORD,1562,1 +LTP093,3,13,REC_WORD,1347,2 +LTP093,3,13,REC_WORD,1048,19 +LTP093,3,13,REC_WORD,254,20 +LTP093,3,13,REC_WORD,1580,6 +LTP093,3,14,WORD,1171,1 +LTP093,3,14,WORD,134,2 +LTP093,3,14,WORD,162,3 +LTP093,3,14,WORD,484,4 +LTP093,3,14,WORD,519,5 +LTP093,3,14,WORD,408,6 +LTP093,3,14,WORD,100,7 +LTP093,3,14,WORD,873,8 +LTP093,3,14,WORD,684,9 +LTP093,3,14,WORD,413,10 +LTP093,3,14,WORD,496,11 +LTP093,3,14,WORD,980,12 +LTP093,3,14,WORD,1351,13 +LTP093,3,14,WORD,292,14 +LTP093,3,14,WORD,869,15 +LTP093,3,14,WORD,1468,16 +LTP093,3,14,WORD,1086,17 +LTP093,3,14,WORD,1508,18 +LTP093,3,14,WORD,1512,19 +LTP093,3,14,WORD,1578,20 +LTP093,3,14,WORD,353,21 +LTP093,3,14,WORD,1119,22 +LTP093,3,14,WORD,1061,23 +LTP093,3,14,WORD,654,24 +LTP093,3,14,REC_WORD,1171,1 +LTP093,3,14,REC_WORD,134,2 +LTP093,3,14,REC_WORD,1512,19 +LTP093,3,14,REC_WORD,1578,20 +LTP093,3,14,REC_WORD,684,9 +LTP093,3,14,REC_WORD,413,10 +LTP093,3,14,REC_WORD,496,11 +LTP093,3,14,REC_WORD,980,12 +LTP093,3,14,REC_WORD,1351,13 +LTP093,3,14,REC_WORD,292,14 +LTP093,3,14,REC_WORD,869,15 +LTP093,3,14,REC_WORD,1086,17 +LTP093,3,14,REC_WORD,1468,16 +LTP093,3,14,REC_WORD,1508,18 +LTP093,3,14,REC_WORD,162,3 +LTP093,3,14,REC_WORD,484,4 +LTP093,3,14,REC_WORD,519,5 +LTP093,3,14,REC_WORD,408,6 +LTP093,3,14,REC_WORD,100,7 +LTP093,3,14,REC_WORD,873,8 +LTP093,3,14,REC_WORD,353,21 +LTP093,3,14,REC_WORD,1119,22 +LTP093,3,15,WORD,295,1 +LTP093,3,15,WORD,315,2 +LTP093,3,15,WORD,1392,3 +LTP093,3,15,WORD,1002,4 +LTP093,3,15,WORD,442,5 +LTP093,3,15,WORD,437,6 +LTP093,3,15,WORD,614,7 +LTP093,3,15,WORD,1438,8 +LTP093,3,15,WORD,1522,9 +LTP093,3,15,WORD,63,10 +LTP093,3,15,WORD,467,11 +LTP093,3,15,WORD,397,12 +LTP093,3,15,WORD,35,13 +LTP093,3,15,WORD,908,14 +LTP093,3,15,WORD,1148,15 +LTP093,3,15,WORD,283,16 +LTP093,3,15,WORD,792,17 +LTP093,3,15,WORD,1246,18 +LTP093,3,15,WORD,1184,19 +LTP093,3,15,WORD,1037,20 +LTP093,3,15,WORD,692,21 +LTP093,3,15,WORD,431,22 +LTP093,3,15,WORD,499,23 +LTP093,3,15,WORD,782,24 +LTP093,3,15,REC_WORD,782,24 +LTP093,3,15,REC_WORD,1184,19 +LTP093,3,15,REC_WORD,692,21 +LTP093,3,16,WORD,760,1 +LTP093,3,16,WORD,61,2 +LTP093,3,16,WORD,75,3 +LTP093,3,16,WORD,127,4 +LTP093,3,16,WORD,708,5 +LTP093,3,16,WORD,972,6 +LTP093,3,16,WORD,253,7 +LTP093,3,16,WORD,386,8 +LTP093,3,16,WORD,999,9 +LTP093,3,16,WORD,1472,10 +LTP093,3,16,WORD,846,11 +LTP093,3,16,WORD,512,12 +LTP093,3,16,WORD,1349,13 +LTP093,3,16,WORD,947,14 +LTP093,3,16,WORD,872,15 +LTP093,3,16,WORD,1272,16 +LTP093,3,16,WORD,1511,17 +LTP093,3,16,WORD,1047,18 +LTP093,3,16,WORD,143,19 +LTP093,3,16,WORD,1555,20 +LTP093,3,16,WORD,1271,21 +LTP093,3,16,WORD,1017,22 +LTP093,3,16,WORD,870,23 +LTP093,3,16,WORD,494,24 +LTP093,3,16,REC_WORD,1511,17 +LTP093,3,16,REC_WORD,1047,18 +LTP093,3,16,REC_WORD,872,15 +LTP093,3,16,REC_WORD,1272,16 +LTP093,3,16,REC_WORD,253,7 +LTP093,3,16,REC_WORD,760,1 +LTP093,3,16,REC_WORD,61,2 +LTP093,3,16,REC_WORD,870,23 +LTP093,3,16,REC_WORD,494,24 +LTP093,3,17,WORD,91,1 +LTP093,3,17,WORD,159,2 +LTP093,3,17,WORD,997,3 +LTP093,3,17,WORD,447,4 +LTP093,3,17,WORD,848,5 +LTP093,3,17,WORD,348,6 +LTP093,3,17,WORD,728,7 +LTP093,3,17,WORD,1620,8 +LTP093,3,17,WORD,390,9 +LTP093,3,17,WORD,194,10 +LTP093,3,17,WORD,593,11 +LTP093,3,17,WORD,659,12 +LTP093,3,17,WORD,987,13 +LTP093,3,17,WORD,790,14 +LTP093,3,17,WORD,578,15 +LTP093,3,17,WORD,1087,16 +LTP093,3,17,WORD,216,17 +LTP093,3,17,WORD,1341,18 +LTP093,3,17,WORD,1533,19 +LTP093,3,17,WORD,168,20 +LTP093,3,17,WORD,211,21 +LTP093,3,17,WORD,1295,22 +LTP093,3,17,WORD,490,23 +LTP093,3,17,WORD,1071,24 +LTP093,3,17,REC_WORD,1533,19 +LTP093,3,17,REC_WORD,168,20 +LTP093,3,17,REC_WORD,1071,24 +LTP093,3,17,REC_WORD,211,21 +LTP093,3,17,REC_WORD,447,4 +LTP093,3,17,REC_WORD,848,5 +LTP093,3,17,REC_WORD,593,11 +LTP093,3,17,REC_WORD,987,13 +LTP093,3,17,REC_WORD,194,10 +LTP093,3,17,REC_WORD,390,9 +LTP093,3,17,REC_WORD,659,12 +LTP093,3,17,REC_WORD,194,10 +LTP093,3,17,REC_WORD,159,2 +LTP093,3,17,REC_WORD,997,3 +LTP093,3,17,REC_WORD,848,5 +LTP093,3,17,REC_WORD,216,17 +LTP093,3,17,REC_WORD,1341,18 +LTP093,3,17,REC_WORD,1087,16 +LTP093,3,18,WORD,733,1 +LTP093,3,18,WORD,635,2 +LTP093,3,18,WORD,230,3 +LTP093,3,18,WORD,1501,4 +LTP093,3,18,WORD,82,5 +LTP093,3,18,WORD,1606,6 +LTP093,3,18,WORD,1448,7 +LTP093,3,18,WORD,1330,8 +LTP093,3,18,WORD,839,9 +LTP093,3,18,WORD,1374,10 +LTP093,3,18,WORD,360,11 +LTP093,3,18,WORD,179,12 +LTP093,3,18,WORD,1536,13 +LTP093,3,18,WORD,1088,14 +LTP093,3,18,WORD,738,15 +LTP093,3,18,WORD,139,16 +LTP093,3,18,WORD,307,17 +LTP093,3,18,WORD,425,18 +LTP093,3,18,WORD,427,19 +LTP093,3,18,WORD,919,20 +LTP093,3,18,WORD,575,21 +LTP093,3,18,WORD,1422,22 +LTP093,3,18,WORD,1173,23 +LTP093,3,18,WORD,745,24 +LTP093,3,18,REC_WORD,1422,22 +LTP093,3,18,REC_WORD,1173,23 +LTP093,3,18,REC_WORD,745,24 +LTP093,3,18,REC_WORD,230,3 +LTP093,3,18,REC_WORD,1501,4 +LTP093,3,18,REC_WORD,733,1 +LTP093,3,18,REC_WORD,1448,7 +LTP093,3,18,REC_WORD,1330,8 +LTP093,3,18,REC_WORD,839,9 +LTP093,3,18,REC_WORD,82,5 +LTP093,3,18,REC_WORD,-1,-999 +LTP093,3,19,WORD,662,1 +LTP093,3,19,WORD,624,2 +LTP093,3,19,WORD,1152,3 +LTP093,3,19,WORD,384,4 +LTP093,3,19,WORD,1414,5 +LTP093,3,19,WORD,1243,6 +LTP093,3,19,WORD,119,7 +LTP093,3,19,WORD,1384,8 +LTP093,3,19,WORD,645,9 +LTP093,3,19,WORD,39,10 +LTP093,3,19,WORD,1093,11 +LTP093,3,19,WORD,1076,12 +LTP093,3,19,WORD,188,13 +LTP093,3,19,WORD,1006,14 +LTP093,3,19,WORD,843,15 +LTP093,3,19,WORD,299,16 +LTP093,3,19,WORD,1060,17 +LTP093,3,19,WORD,1385,18 +LTP093,3,19,WORD,12,19 +LTP093,3,19,WORD,1635,20 +LTP093,3,19,WORD,1065,21 +LTP093,3,19,WORD,963,22 +LTP093,3,19,WORD,1049,23 +LTP093,3,19,WORD,1258,24 +LTP093,3,19,REC_WORD,963,22 +LTP093,3,19,REC_WORD,1049,23 +LTP093,3,19,REC_WORD,1258,24 +LTP093,3,19,REC_WORD,1384,8 +LTP093,3,19,REC_WORD,645,9 +LTP093,3,19,REC_WORD,1243,6 +LTP093,3,19,REC_WORD,384,4 +LTP093,3,19,REC_WORD,39,10 +LTP093,3,19,REC_WORD,1093,11 +LTP093,3,20,WORD,960,1 +LTP093,3,20,WORD,53,2 +LTP093,3,20,WORD,1416,3 +LTP093,3,20,WORD,325,4 +LTP093,3,20,WORD,66,5 +LTP093,3,20,WORD,372,6 +LTP093,3,20,WORD,5,7 +LTP093,3,20,WORD,878,8 +LTP093,3,20,WORD,1035,9 +LTP093,3,20,WORD,378,10 +LTP093,3,20,WORD,1149,11 +LTP093,3,20,WORD,1461,12 +LTP093,3,20,WORD,340,13 +LTP093,3,20,WORD,1373,14 +LTP093,3,20,WORD,713,15 +LTP093,3,20,WORD,1636,16 +LTP093,3,20,WORD,570,17 +LTP093,3,20,WORD,265,18 +LTP093,3,20,WORD,261,19 +LTP093,3,20,WORD,1317,20 +LTP093,3,20,WORD,807,21 +LTP093,3,20,WORD,1111,22 +LTP093,3,20,WORD,1229,23 +LTP093,3,20,WORD,994,24 +LTP093,3,20,REC_WORD,1229,23 +LTP093,3,20,REC_WORD,994,24 +LTP093,3,20,REC_WORD,261,19 +LTP093,3,20,REC_WORD,1317,20 +LTP093,3,20,REC_WORD,570,17 +LTP093,3,20,REC_WORD,265,18 +LTP093,3,20,REC_WORD,960,1 +LTP093,3,20,REC_WORD,1416,3 +LTP093,3,20,REC_WORD,53,2 +LTP093,3,20,REC_WORD,325,4 +LTP093,3,20,REC_WORD,-1,-999 +LTP093,3,20,REC_WORD,149,-999 +LTP093,3,20,REC_WORD,5,7 +LTP093,3,21,WORD,142,1 +LTP093,3,21,WORD,1238,2 +LTP093,3,21,WORD,508,3 +LTP093,3,21,WORD,488,4 +LTP093,3,21,WORD,466,5 +LTP093,3,21,WORD,401,6 +LTP093,3,21,WORD,1608,7 +LTP093,3,21,WORD,1019,8 +LTP093,3,21,WORD,600,9 +LTP093,3,21,WORD,559,10 +LTP093,3,21,WORD,1013,11 +LTP093,3,21,WORD,734,12 +LTP093,3,21,WORD,133,13 +LTP093,3,21,WORD,84,14 +LTP093,3,21,WORD,368,15 +LTP093,3,21,WORD,809,16 +LTP093,3,21,WORD,169,17 +LTP093,3,21,WORD,778,18 +LTP093,3,21,WORD,1388,19 +LTP093,3,21,WORD,1066,20 +LTP093,3,21,WORD,1331,21 +LTP093,3,21,WORD,400,22 +LTP093,3,21,WORD,405,23 +LTP093,3,21,WORD,702,24 +LTP093,3,21,REC_WORD,1388,19 +LTP093,3,21,REC_WORD,1066,20 +LTP093,3,21,REC_WORD,778,18 +LTP093,3,21,REC_WORD,1331,21 +LTP093,3,21,REC_WORD,400,22 +LTP093,3,22,WORD,982,1 +LTP093,3,22,WORD,699,2 +LTP093,3,22,WORD,804,3 +LTP093,3,22,WORD,639,4 +LTP093,3,22,WORD,145,5 +LTP093,3,22,WORD,439,6 +LTP093,3,22,WORD,1565,7 +LTP093,3,22,WORD,861,8 +LTP093,3,22,WORD,483,9 +LTP093,3,22,WORD,1125,10 +LTP093,3,22,WORD,1227,11 +LTP093,3,22,WORD,255,12 +LTP093,3,22,WORD,820,13 +LTP093,3,22,WORD,1299,14 +LTP093,3,22,WORD,485,15 +LTP093,3,22,WORD,395,16 +LTP093,3,22,WORD,248,17 +LTP093,3,22,WORD,94,18 +LTP093,3,22,WORD,530,19 +LTP093,3,22,WORD,785,20 +LTP093,3,22,WORD,1503,21 +LTP093,3,22,WORD,658,22 +LTP093,3,22,WORD,579,23 +LTP093,3,22,WORD,435,24 +LTP093,3,22,REC_WORD,1503,21 +LTP093,3,22,REC_WORD,658,22 +LTP093,3,22,REC_WORD,248,17 +LTP093,3,22,REC_WORD,94,18 +LTP093,3,22,REC_WORD,485,15 +LTP093,3,22,REC_WORD,395,16 +LTP093,3,22,REC_WORD,982,1 +LTP093,3,22,REC_WORD,699,2 +LTP093,3,22,REC_WORD,804,3 +LTP093,3,22,REC_WORD,639,4 +LTP093,3,23,WORD,1423,1 +LTP093,3,23,WORD,1143,2 +LTP093,3,23,WORD,763,3 +LTP093,3,23,WORD,6,4 +LTP093,3,23,WORD,1075,5 +LTP093,3,23,WORD,1192,6 +LTP093,3,23,WORD,373,7 +LTP093,3,23,WORD,1113,8 +LTP093,3,23,WORD,1132,9 +LTP093,3,23,WORD,793,10 +LTP093,3,23,WORD,1628,11 +LTP093,3,23,WORD,509,12 +LTP093,3,23,WORD,1032,13 +LTP093,3,23,WORD,929,14 +LTP093,3,23,WORD,164,15 +LTP093,3,23,WORD,177,16 +LTP093,3,23,WORD,1079,17 +LTP093,3,23,WORD,1515,18 +LTP093,3,23,WORD,1357,19 +LTP093,3,23,WORD,1108,20 +LTP093,3,23,WORD,718,21 +LTP093,3,23,WORD,1629,22 +LTP093,3,23,WORD,1089,23 +LTP093,3,23,WORD,916,24 +LTP093,3,23,REC_WORD,1629,22 +LTP093,3,23,REC_WORD,1089,23 +LTP093,3,23,REC_WORD,916,24 +LTP093,3,23,REC_WORD,1515,18 +LTP093,3,23,REC_WORD,509,12 +LTP093,3,23,REC_WORD,1628,11 +LTP093,3,24,WORD,543,1 +LTP093,3,24,WORD,541,2 +LTP093,3,24,WORD,46,3 +LTP093,3,24,WORD,1488,4 +LTP093,3,24,WORD,857,5 +LTP093,3,24,WORD,576,6 +LTP093,3,24,WORD,1329,7 +LTP093,3,24,WORD,1403,8 +LTP093,3,24,WORD,55,9 +LTP093,3,24,WORD,313,10 +LTP093,3,24,WORD,641,11 +LTP093,3,24,WORD,392,12 +LTP093,3,24,WORD,1256,13 +LTP093,3,24,WORD,852,14 +LTP093,3,24,WORD,157,15 +LTP093,3,24,WORD,1332,16 +LTP093,3,24,WORD,834,17 +LTP093,3,24,WORD,249,18 +LTP093,3,24,WORD,113,19 +LTP093,3,24,WORD,1370,20 +LTP093,3,24,WORD,1592,21 +LTP093,3,24,WORD,546,22 +LTP093,3,24,WORD,602,23 +LTP093,3,24,WORD,605,24 +LTP093,3,24,REC_WORD,602,23 +LTP093,3,24,REC_WORD,605,24 +LTP093,3,24,REC_WORD,834,17 +LTP093,3,24,REC_WORD,1329,7 +LTP093,3,24,REC_WORD,641,11 +LTP093,3,24,REC_WORD,1332,16 +LTP093,3,24,REC_WORD,157,15 +LTP093,3,24,REC_WORD,541,2 +LTP093,3,24,REC_WORD,543,1 +LTP093,3,24,REC_WORD,46,3 +LTP093,3,24,REC_WORD,1488,4 +LTP093,3,24,REC_WORD,852,14 +LTP093,3,24,REC_WORD,55,9 +LTP093,3,24,REC_WORD,313,10 +LTP093,3,24,REC_WORD,-1,-999 +LTP093,3,24,REC_WORD,1256,13 +LTP093,4,1,WORD,1070,1 +LTP093,4,1,WORD,113,2 +LTP093,4,1,WORD,1351,3 +LTP093,4,1,WORD,1636,4 +LTP093,4,1,WORD,446,5 +LTP093,4,1,WORD,662,6 +LTP093,4,1,WORD,1593,7 +LTP093,4,1,WORD,187,8 +LTP093,4,1,WORD,1631,9 +LTP093,4,1,WORD,800,10 +LTP093,4,1,WORD,919,11 +LTP093,4,1,WORD,972,12 +LTP093,4,1,WORD,833,13 +LTP093,4,1,WORD,852,14 +LTP093,4,1,WORD,1368,15 +LTP093,4,1,WORD,1009,16 +LTP093,4,1,WORD,1085,17 +LTP093,4,1,WORD,718,18 +LTP093,4,1,WORD,820,19 +LTP093,4,1,WORD,732,20 +LTP093,4,1,WORD,1292,21 +LTP093,4,1,WORD,108,22 +LTP093,4,1,WORD,35,23 +LTP093,4,1,WORD,12,24 +LTP093,4,1,REC_WORD,820,19 +LTP093,4,1,REC_WORD,732,20 +LTP093,4,1,REC_WORD,35,23 +LTP093,4,1,REC_WORD,108,22 +LTP093,4,1,REC_WORD,1070,1 +LTP093,4,1,REC_WORD,113,2 +LTP093,4,1,REC_WORD,1593,7 +LTP093,4,1,REC_WORD,187,8 +LTP093,4,1,REC_WORD,1009,16 +LTP093,4,1,REC_WORD,718,18 +LTP093,4,1,REC_WORD,662,6 +LTP093,4,1,REC_WORD,446,5 +LTP093,4,2,WORD,386,1 +LTP093,4,2,WORD,1104,2 +LTP093,4,2,WORD,633,3 +LTP093,4,2,WORD,697,4 +LTP093,4,2,WORD,776,5 +LTP093,4,2,WORD,1544,6 +LTP093,4,2,WORD,1357,7 +LTP093,4,2,WORD,1036,8 +LTP093,4,2,WORD,1071,9 +LTP093,4,2,WORD,415,10 +LTP093,4,2,WORD,620,11 +LTP093,4,2,WORD,1301,12 +LTP093,4,2,WORD,6,13 +LTP093,4,2,WORD,590,14 +LTP093,4,2,WORD,139,15 +LTP093,4,2,WORD,1468,16 +LTP093,4,2,WORD,1037,17 +LTP093,4,2,WORD,125,18 +LTP093,4,2,WORD,764,19 +LTP093,4,2,WORD,866,20 +LTP093,4,2,WORD,240,21 +LTP093,4,2,WORD,883,22 +LTP093,4,2,WORD,179,23 +LTP093,4,2,WORD,1125,24 +LTP093,4,2,REC_WORD,179,23 +LTP093,4,2,REC_WORD,1125,24 +LTP093,4,2,REC_WORD,1301,12 +LTP093,4,2,REC_WORD,883,22 +LTP093,4,2,REC_WORD,240,21 +LTP093,4,2,REC_WORD,764,19 +LTP093,4,2,REC_WORD,866,20 +LTP093,4,2,REC_WORD,620,11 +LTP093,4,2,REC_WORD,633,3 +LTP093,4,2,REC_WORD,697,4 +LTP093,4,2,REC_WORD,776,5 +LTP093,4,2,REC_WORD,1544,6 +LTP093,4,2,REC_WORD,386,1 +LTP093,4,2,REC_WORD,1104,2 +LTP093,4,2,REC_WORD,1071,9 +LTP093,4,3,WORD,599,1 +LTP093,4,3,WORD,1087,2 +LTP093,4,3,WORD,1095,3 +LTP093,4,3,WORD,977,4 +LTP093,4,3,WORD,1159,5 +LTP093,4,3,WORD,1243,6 +LTP093,4,3,WORD,901,7 +LTP093,4,3,WORD,955,8 +LTP093,4,3,WORD,576,9 +LTP093,4,3,WORD,280,10 +LTP093,4,3,WORD,1608,11 +LTP093,4,3,WORD,1562,12 +LTP093,4,3,WORD,1451,13 +LTP093,4,3,WORD,1414,14 +LTP093,4,3,WORD,199,15 +LTP093,4,3,WORD,1519,16 +LTP093,4,3,WORD,308,17 +LTP093,4,3,WORD,216,18 +LTP093,4,3,WORD,1086,19 +LTP093,4,3,WORD,484,20 +LTP093,4,3,WORD,1000,21 +LTP093,4,3,WORD,1251,22 +LTP093,4,3,WORD,136,23 +LTP093,4,3,WORD,1333,24 +LTP093,4,3,REC_WORD,599,1 +LTP093,4,3,REC_WORD,1087,2 +LTP093,4,3,REC_WORD,484,20 +LTP093,4,3,REC_WORD,1333,24 +LTP093,4,3,REC_WORD,136,23 +LTP093,4,3,REC_WORD,1251,22 +LTP093,4,3,REC_WORD,1608,11 +LTP093,4,3,REC_WORD,1562,12 +LTP093,4,3,REC_WORD,1451,13 +LTP093,4,3,REC_WORD,199,15 +LTP093,4,3,REC_WORD,1414,14 +LTP093,4,3,REC_WORD,1519,16 +LTP093,4,4,WORD,323,1 +LTP093,4,4,WORD,708,2 +LTP093,4,4,WORD,86,3 +LTP093,4,4,WORD,771,4 +LTP093,4,4,WORD,1511,5 +LTP093,4,4,WORD,408,6 +LTP093,4,4,WORD,371,7 +LTP093,4,4,WORD,384,8 +LTP093,4,4,WORD,501,9 +LTP093,4,4,WORD,1427,10 +LTP093,4,4,WORD,999,11 +LTP093,4,4,WORD,622,12 +LTP093,4,4,WORD,13,13 +LTP093,4,4,WORD,1232,14 +LTP093,4,4,WORD,1260,15 +LTP093,4,4,WORD,373,16 +LTP093,4,4,WORD,10,17 +LTP093,4,4,WORD,137,18 +LTP093,4,4,WORD,336,19 +LTP093,4,4,WORD,1194,20 +LTP093,4,4,WORD,1426,21 +LTP093,4,4,WORD,1096,22 +LTP093,4,4,WORD,1015,23 +LTP093,4,4,WORD,210,24 +LTP093,4,4,REC_WORD,1426,21 +LTP093,4,4,REC_WORD,1096,22 +LTP093,4,4,REC_WORD,336,19 +LTP093,4,4,REC_WORD,210,24 +LTP093,4,4,REC_WORD,10,17 +LTP093,4,4,REC_WORD,137,18 +LTP093,4,4,REC_WORD,999,11 +LTP093,4,4,REC_WORD,622,12 +LTP093,4,5,WORD,171,1 +LTP093,4,5,WORD,1520,2 +LTP093,4,5,WORD,1388,3 +LTP093,4,5,WORD,976,4 +LTP093,4,5,WORD,368,5 +LTP093,4,5,WORD,1486,6 +LTP093,4,5,WORD,559,7 +LTP093,4,5,WORD,338,8 +LTP093,4,5,WORD,1044,9 +LTP093,4,5,WORD,395,10 +LTP093,4,5,WORD,200,11 +LTP093,4,5,WORD,546,12 +LTP093,4,5,WORD,1395,13 +LTP093,4,5,WORD,143,14 +LTP093,4,5,WORD,1152,15 +LTP093,4,5,WORD,1027,16 +LTP093,4,5,WORD,1347,17 +LTP093,4,5,WORD,1006,18 +LTP093,4,5,WORD,168,19 +LTP093,4,5,WORD,593,20 +LTP093,4,5,WORD,405,21 +LTP093,4,5,WORD,530,22 +LTP093,4,5,WORD,508,23 +LTP093,4,5,WORD,645,24 +LTP093,4,5,REC_WORD,1006,18 +LTP093,4,5,REC_WORD,593,20 +LTP093,4,5,REC_WORD,168,19 +LTP093,4,5,REC_WORD,405,21 +LTP093,4,5,REC_WORD,530,22 +LTP093,4,5,REC_WORD,508,23 +LTP093,4,5,REC_WORD,645,24 +LTP093,4,5,REC_WORD,1152,15 +LTP093,4,5,REC_WORD,1027,16 +LTP093,4,5,REC_WORD,1347,17 +LTP093,4,5,REC_WORD,1520,2 +LTP093,4,5,REC_WORD,171,1 +LTP093,4,5,REC_WORD,1388,3 +LTP093,4,5,REC_WORD,976,4 +LTP093,4,5,REC_WORD,1044,9 +LTP093,4,5,REC_WORD,395,10 +LTP093,4,5,REC_WORD,200,11 +LTP093,4,5,REC_WORD,1486,6 +LTP093,4,6,WORD,858,1 +LTP093,4,6,WORD,223,2 +LTP093,4,6,WORD,358,3 +LTP093,4,6,WORD,1416,4 +LTP093,4,6,WORD,702,5 +LTP093,4,6,WORD,29,6 +LTP093,4,6,WORD,172,7 +LTP093,4,6,WORD,874,8 +LTP093,4,6,WORD,932,9 +LTP093,4,6,WORD,519,10 +LTP093,4,6,WORD,278,11 +LTP093,4,6,WORD,104,12 +LTP093,4,6,WORD,798,13 +LTP093,4,6,WORD,417,14 +LTP093,4,6,WORD,639,15 +LTP093,4,6,WORD,1611,16 +LTP093,4,6,WORD,796,17 +LTP093,4,6,WORD,861,18 +LTP093,4,6,WORD,575,19 +LTP093,4,6,WORD,1140,20 +LTP093,4,6,WORD,1526,21 +LTP093,4,6,WORD,520,22 +LTP093,4,6,WORD,340,23 +LTP093,4,6,WORD,253,24 +LTP093,4,6,REC_WORD,1526,21 +LTP093,4,6,REC_WORD,520,22 +LTP093,4,6,REC_WORD,340,23 +LTP093,4,6,REC_WORD,861,18 +LTP093,4,6,REC_WORD,575,19 +LTP093,4,6,REC_WORD,1140,20 +LTP093,4,6,REC_WORD,1416,4 +LTP093,4,6,REC_WORD,29,6 +LTP093,4,6,REC_WORD,874,8 +LTP093,4,6,REC_WORD,519,10 +LTP093,4,6,REC_WORD,932,9 +LTP093,4,6,REC_WORD,278,11 +LTP093,4,6,REC_WORD,639,15 +LTP093,4,6,REC_WORD,1611,16 +LTP093,4,6,REC_WORD,796,17 +LTP093,4,7,WORD,1293,1 +LTP093,4,7,WORD,203,2 +LTP093,4,7,WORD,755,3 +LTP093,4,7,WORD,996,4 +LTP093,4,7,WORD,1202,5 +LTP093,4,7,WORD,388,6 +LTP093,4,7,WORD,1035,7 +LTP093,4,7,WORD,485,8 +LTP093,4,7,WORD,579,9 +LTP093,4,7,WORD,46,10 +LTP093,4,7,WORD,995,11 +LTP093,4,7,WORD,315,12 +LTP093,4,7,WORD,1501,13 +LTP093,4,7,WORD,1108,14 +LTP093,4,7,WORD,1358,15 +LTP093,4,7,WORD,389,16 +LTP093,4,7,WORD,211,17 +LTP093,4,7,WORD,1197,18 +LTP093,4,7,WORD,659,19 +LTP093,4,7,WORD,1287,20 +LTP093,4,7,WORD,553,21 +LTP093,4,7,WORD,441,22 +LTP093,4,7,WORD,1408,23 +LTP093,4,7,WORD,974,24 +LTP093,4,7,REC_WORD,659,19 +LTP093,4,7,REC_WORD,1287,20 +LTP093,4,7,REC_WORD,553,21 +LTP093,4,7,REC_WORD,389,16 +LTP093,4,7,REC_WORD,211,17 +LTP093,4,7,REC_WORD,1197,18 +LTP093,4,7,REC_WORD,996,4 +LTP093,4,7,REC_WORD,1202,5 +LTP093,4,7,REC_WORD,388,6 +LTP093,4,7,REC_WORD,1035,7 +LTP093,4,7,REC_WORD,485,8 +LTP093,4,7,REC_WORD,579,9 +LTP093,4,7,REC_WORD,46,10 +LTP093,4,7,REC_WORD,995,11 +LTP093,4,7,REC_WORD,315,12 +LTP093,4,7,REC_WORD,1293,1 +LTP093,4,7,REC_WORD,203,2 +LTP093,4,7,REC_WORD,755,3 +LTP093,4,8,WORD,348,1 +LTP093,4,8,WORD,872,2 +LTP093,4,8,WORD,1319,3 +LTP093,4,8,WORD,792,4 +LTP093,4,8,WORD,1016,5 +LTP093,4,8,WORD,839,6 +LTP093,4,8,WORD,1080,7 +LTP093,4,8,WORD,383,8 +LTP093,4,8,WORD,1505,9 +LTP093,4,8,WORD,134,10 +LTP093,4,8,WORD,1423,11 +LTP093,4,8,WORD,738,12 +LTP093,4,8,WORD,1572,13 +LTP093,4,8,WORD,1147,14 +LTP093,4,8,WORD,580,15 +LTP093,4,8,WORD,407,16 +LTP093,4,8,WORD,908,17 +LTP093,4,8,WORD,1048,18 +LTP093,4,8,WORD,869,19 +LTP093,4,8,WORD,829,20 +LTP093,4,8,WORD,912,21 +LTP093,4,8,WORD,1621,22 +LTP093,4,8,WORD,1158,23 +LTP093,4,8,WORD,483,24 +LTP093,4,8,REC_WORD,1621,22 +LTP093,4,8,REC_WORD,1158,23 +LTP093,4,8,REC_WORD,483,24 +LTP093,4,8,REC_WORD,869,19 +LTP093,4,8,REC_WORD,829,20 +LTP093,4,8,REC_WORD,912,21 +LTP093,4,8,REC_WORD,1080,7 +LTP093,4,8,REC_WORD,383,8 +LTP093,4,8,REC_WORD,1505,9 +LTP093,4,9,WORD,1076,1 +LTP093,4,9,WORD,627,2 +LTP093,4,9,WORD,1089,3 +LTP093,4,9,WORD,33,4 +LTP093,4,9,WORD,1411,5 +LTP093,4,9,WORD,637,6 +LTP093,4,9,WORD,265,7 +LTP093,4,9,WORD,1124,8 +LTP093,4,9,WORD,5,9 +LTP093,4,9,WORD,916,10 +LTP093,4,9,WORD,641,11 +LTP093,4,9,WORD,719,12 +LTP093,4,9,WORD,1369,13 +LTP093,4,9,WORD,1345,14 +LTP093,4,9,WORD,878,15 +LTP093,4,9,WORD,893,16 +LTP093,4,9,WORD,327,17 +LTP093,4,9,WORD,254,18 +LTP093,4,9,WORD,390,19 +LTP093,4,9,WORD,1011,20 +LTP093,4,9,WORD,175,21 +LTP093,4,9,WORD,1057,22 +LTP093,4,9,WORD,980,23 +LTP093,4,9,WORD,1580,24 +LTP093,4,9,REC_WORD,1057,22 +LTP093,4,9,REC_WORD,980,23 +LTP093,4,9,REC_WORD,1580,24 +LTP093,4,9,REC_WORD,1369,13 +LTP093,4,9,REC_WORD,1345,14 +LTP093,4,9,REC_WORD,878,15 +LTP093,4,9,REC_WORD,916,10 +LTP093,4,9,REC_WORD,641,11 +LTP093,4,9,REC_WORD,719,12 +LTP093,4,9,REC_WORD,265,7 +LTP093,4,9,REC_WORD,1124,8 +LTP093,4,9,REC_WORD,5,9 +LTP093,4,9,REC_WORD,33,4 +LTP093,4,9,REC_WORD,1411,5 +LTP093,4,9,REC_WORD,637,6 +LTP093,4,9,REC_WORD,327,17 +LTP093,4,9,REC_WORD,893,16 +LTP093,4,9,REC_WORD,254,18 +LTP093,4,9,REC_WORD,1076,1 +LTP093,4,9,REC_WORD,627,2 +LTP093,4,9,REC_WORD,1089,3 +LTP093,4,10,WORD,997,1 +LTP093,4,10,WORD,658,2 +LTP093,4,10,WORD,1628,3 +LTP093,4,10,WORD,642,4 +LTP093,4,10,WORD,635,5 +LTP093,4,10,WORD,1075,6 +LTP093,4,10,WORD,1371,7 +LTP093,4,10,WORD,1113,8 +LTP093,4,10,WORD,963,9 +LTP093,4,10,WORD,1192,10 +LTP093,4,10,WORD,1238,11 +LTP093,4,10,WORD,888,12 +LTP093,4,10,WORD,68,13 +LTP093,4,10,WORD,400,14 +LTP093,4,10,WORD,1246,15 +LTP093,4,10,WORD,734,16 +LTP093,4,10,WORD,585,17 +LTP093,4,10,WORD,804,18 +LTP093,4,10,WORD,1478,19 +LTP093,4,10,WORD,360,20 +LTP093,4,10,WORD,1508,21 +LTP093,4,10,WORD,184,22 +LTP093,4,10,WORD,1271,23 +LTP093,4,10,WORD,188,24 +LTP093,4,10,REC_WORD,184,22 +LTP093,4,10,REC_WORD,1271,23 +LTP093,4,10,REC_WORD,188,24 +LTP093,4,10,REC_WORD,1478,19 +LTP093,4,10,REC_WORD,360,20 +LTP093,4,10,REC_WORD,1508,21 +LTP093,4,10,REC_WORD,658,2 +LTP093,4,10,REC_WORD,635,5 +LTP093,4,10,REC_WORD,642,4 +LTP093,4,10,REC_WORD,1075,6 +LTP093,4,10,REC_WORD,1192,10 +LTP093,4,10,REC_WORD,734,16 +LTP093,4,10,REC_WORD,585,17 +LTP093,4,10,REC_WORD,804,18 +LTP093,4,11,WORD,304,1 +LTP093,4,11,WORD,1284,2 +LTP093,4,11,WORD,785,3 +LTP093,4,11,WORD,959,4 +LTP093,4,11,WORD,127,5 +LTP093,4,11,WORD,1456,6 +LTP093,4,11,WORD,684,7 +LTP093,4,11,WORD,1545,8 +LTP093,4,11,WORD,235,9 +LTP093,4,11,WORD,109,10 +LTP093,4,11,WORD,1587,11 +LTP093,4,11,WORD,1307,12 +LTP093,4,11,WORD,605,13 +LTP093,4,11,WORD,1149,14 +LTP093,4,11,WORD,1031,15 +LTP093,4,11,WORD,847,16 +LTP093,4,11,WORD,1415,17 +LTP093,4,11,WORD,543,18 +LTP093,4,11,WORD,783,19 +LTP093,4,11,WORD,1013,20 +LTP093,4,11,WORD,1061,21 +LTP093,4,11,WORD,1176,22 +LTP093,4,11,WORD,447,23 +LTP093,4,11,WORD,1098,24 +LTP093,4,11,REC_WORD,1176,22 +LTP093,4,11,REC_WORD,447,23 +LTP093,4,11,REC_WORD,1098,24 +LTP093,4,11,REC_WORD,783,19 +LTP093,4,11,REC_WORD,1013,20 +LTP093,4,11,REC_WORD,1061,21 +LTP093,4,11,REC_WORD,304,1 +LTP093,4,11,REC_WORD,1284,2 +LTP093,4,11,REC_WORD,785,3 +LTP093,4,11,REC_WORD,959,4 +LTP093,4,11,REC_WORD,127,5 +LTP093,4,11,REC_WORD,1456,6 +LTP093,4,11,REC_WORD,847,16 +LTP093,4,11,REC_WORD,1415,17 +LTP093,4,11,REC_WORD,543,18 +LTP093,4,11,REC_WORD,109,10 +LTP093,4,11,REC_WORD,1587,11 +LTP093,4,11,REC_WORD,1307,12 +LTP093,4,12,WORD,592,1 +LTP093,4,12,WORD,1629,2 +LTP093,4,12,WORD,353,3 +LTP093,4,12,WORD,752,4 +LTP093,4,12,WORD,1578,5 +LTP093,4,12,WORD,876,6 +LTP093,4,12,WORD,1117,7 +LTP093,4,12,WORD,1535,8 +LTP093,4,12,WORD,782,9 +LTP093,4,12,WORD,1515,10 +LTP093,4,12,WORD,565,11 +LTP093,4,12,WORD,1382,12 +LTP093,4,12,WORD,1224,13 +LTP093,4,12,WORD,814,14 +LTP093,4,12,WORD,591,15 +LTP093,4,12,WORD,1503,16 +LTP093,4,12,WORD,248,17 +LTP093,4,12,WORD,94,18 +LTP093,4,12,WORD,267,19 +LTP093,4,12,WORD,316,20 +LTP093,4,12,WORD,410,21 +LTP093,4,12,WORD,339,22 +LTP093,4,12,WORD,602,23 +LTP093,4,12,WORD,307,24 +LTP093,4,12,REC_WORD,339,22 +LTP093,4,12,REC_WORD,316,20 +LTP093,4,12,REC_WORD,307,24 +LTP093,4,12,REC_WORD,1224,13 +LTP093,4,12,REC_WORD,814,14 +LTP093,4,12,REC_WORD,267,19 +LTP093,4,12,REC_WORD,94,18 +LTP093,4,12,REC_WORD,1117,7 +LTP093,4,13,WORD,1521,1 +LTP093,4,13,WORD,1317,2 +LTP093,4,13,WORD,1633,3 +LTP093,4,13,WORD,793,4 +LTP093,4,13,WORD,706,5 +LTP093,4,13,WORD,1533,6 +LTP093,4,13,WORD,295,7 +LTP093,4,13,WORD,1327,8 +LTP093,4,13,WORD,987,9 +LTP093,4,13,WORD,325,10 +LTP093,4,13,WORD,760,11 +LTP093,4,13,WORD,490,12 +LTP093,4,13,WORD,1262,13 +LTP093,4,13,WORD,821,14 +LTP093,4,13,WORD,1635,15 +LTP093,4,13,WORD,61,16 +LTP093,4,13,WORD,1047,17 +LTP093,4,13,WORD,88,18 +LTP093,4,13,WORD,499,19 +LTP093,4,13,WORD,1312,20 +LTP093,4,13,WORD,801,21 +LTP093,4,13,WORD,1522,22 +LTP093,4,13,WORD,1171,23 +LTP093,4,13,WORD,1422,24 +LTP093,4,13,REC_WORD,1522,22 +LTP093,4,13,REC_WORD,1171,23 +LTP093,4,13,REC_WORD,1422,24 +LTP093,4,13,REC_WORD,499,19 +LTP093,4,13,REC_WORD,1312,20 +LTP093,4,13,REC_WORD,801,21 +LTP093,4,13,REC_WORD,61,16 +LTP093,4,13,REC_WORD,88,18 +LTP093,4,13,REC_WORD,1521,1 +LTP093,4,13,REC_WORD,1317,2 +LTP093,4,13,REC_WORD,1633,3 +LTP093,4,13,REC_WORD,295,7 +LTP093,4,13,REC_WORD,1327,8 +LTP093,4,13,REC_WORD,987,9 +LTP093,4,14,WORD,1605,1 +LTP093,4,14,WORD,435,2 +LTP093,4,14,WORD,1112,3 +LTP093,4,14,WORD,183,4 +LTP093,4,14,WORD,922,5 +LTP093,4,14,WORD,1438,6 +LTP093,4,14,WORD,670,7 +LTP093,4,14,WORD,1299,8 +LTP093,4,14,WORD,848,9 +LTP093,4,14,WORD,733,10 +LTP093,4,14,WORD,929,11 +LTP093,4,14,WORD,728,12 +LTP093,4,14,WORD,1119,13 +LTP093,4,14,WORD,1374,14 +LTP093,4,14,WORD,258,15 +LTP093,4,14,WORD,169,16 +LTP093,4,14,WORD,1403,17 +LTP093,4,14,WORD,496,18 +LTP093,4,14,WORD,1343,19 +LTP093,4,14,WORD,346,20 +LTP093,4,14,WORD,425,21 +LTP093,4,14,WORD,1294,22 +LTP093,4,14,WORD,623,23 +LTP093,4,14,WORD,255,24 +LTP093,4,14,REC_WORD,1343,19 +LTP093,4,14,REC_WORD,346,20 +LTP093,4,14,REC_WORD,425,21 +LTP093,4,14,REC_WORD,1294,22 +LTP093,4,14,REC_WORD,1119,13 +LTP093,4,14,REC_WORD,1374,14 +LTP093,4,14,REC_WORD,258,15 +LTP093,4,14,REC_WORD,733,10 +LTP093,4,14,REC_WORD,728,12 +LTP093,4,15,WORD,1370,1 +LTP093,4,15,WORD,569,2 +LTP093,4,15,WORD,1184,3 +LTP093,4,15,WORD,1405,4 +LTP093,4,15,WORD,598,5 +LTP093,4,15,WORD,1144,6 +LTP093,4,15,WORD,1173,7 +LTP093,4,15,WORD,466,8 +LTP093,4,15,WORD,857,9 +LTP093,4,15,WORD,1407,10 +LTP093,4,15,WORD,715,11 +LTP093,4,15,WORD,754,12 +LTP093,4,15,WORD,1331,13 +LTP093,4,15,WORD,1088,14 +LTP093,4,15,WORD,133,15 +LTP093,4,15,WORD,994,16 +LTP093,4,15,WORD,177,17 +LTP093,4,15,WORD,226,18 +LTP093,4,15,WORD,1242,19 +LTP093,4,15,WORD,157,20 +LTP093,4,15,WORD,498,21 +LTP093,4,15,WORD,1472,22 +LTP093,4,15,WORD,397,23 +LTP093,4,15,WORD,427,24 +LTP093,4,15,REC_WORD,1472,22 +LTP093,4,15,REC_WORD,397,23 +LTP093,4,15,REC_WORD,427,24 +LTP093,4,15,REC_WORD,1242,19 +LTP093,4,15,REC_WORD,157,20 +LTP093,4,15,REC_WORD,498,21 +LTP093,4,15,REC_WORD,1331,13 +LTP093,4,15,REC_WORD,1088,14 +LTP093,4,15,REC_WORD,133,15 +LTP093,4,15,REC_WORD,569,2 +LTP093,4,15,REC_WORD,1370,1 +LTP093,4,15,REC_WORD,1184,3 +LTP093,4,15,REC_WORD,466,8 +LTP093,4,15,REC_WORD,1173,7 +LTP093,4,15,REC_WORD,857,9 +LTP093,4,16,WORD,790,1 +LTP093,4,16,WORD,1592,2 +LTP093,4,16,WORD,849,3 +LTP093,4,16,WORD,100,4 +LTP093,4,16,WORD,795,5 +LTP093,4,16,WORD,1618,6 +LTP093,4,16,WORD,766,7 +LTP093,4,16,WORD,512,8 +LTP093,4,16,WORD,1392,9 +LTP093,4,16,WORD,1256,10 +LTP093,4,16,WORD,55,11 +LTP093,4,16,WORD,723,12 +LTP093,4,16,WORD,749,13 +LTP093,4,16,WORD,1565,14 +LTP093,4,16,WORD,1420,15 +LTP093,4,16,WORD,1315,16 +LTP093,4,16,WORD,261,17 +LTP093,4,16,WORD,1209,18 +LTP093,4,16,WORD,1295,19 +LTP093,4,16,WORD,1060,20 +LTP093,4,16,WORD,683,21 +LTP093,4,16,WORD,667,22 +LTP093,4,16,WORD,66,23 +LTP093,4,16,WORD,873,24 +LTP093,4,16,REC_WORD,667,22 +LTP093,4,16,REC_WORD,66,23 +LTP093,4,16,REC_WORD,873,24 +LTP093,4,16,REC_WORD,1295,19 +LTP093,4,16,REC_WORD,1060,20 +LTP093,4,16,REC_WORD,683,21 +LTP093,4,16,REC_WORD,1315,16 +LTP093,4,16,REC_WORD,1209,18 +LTP093,4,16,REC_WORD,723,12 +LTP093,4,16,REC_WORD,1256,10 +LTP093,4,16,REC_WORD,55,11 +LTP093,4,16,REC_WORD,749,13 +LTP093,4,16,REC_WORD,1565,14 +LTP093,4,16,REC_WORD,1420,15 +LTP093,4,16,REC_WORD,766,7 +LTP093,4,16,REC_WORD,512,8 +LTP093,4,16,REC_WORD,1392,9 +LTP093,4,17,WORD,194,1 +LTP093,4,17,WORD,429,2 +LTP093,4,17,WORD,1493,3 +LTP093,4,17,WORD,1199,4 +LTP093,4,17,WORD,38,5 +LTP093,4,17,WORD,230,6 +LTP093,4,17,WORD,1356,7 +LTP093,4,17,WORD,731,8 +LTP093,4,17,WORD,604,9 +LTP093,4,17,WORD,84,10 +LTP093,4,17,WORD,895,11 +LTP093,4,17,WORD,1022,12 +LTP093,4,17,WORD,1139,13 +LTP093,4,17,WORD,1527,14 +LTP093,4,17,WORD,1332,15 +LTP093,4,17,WORD,960,16 +LTP093,4,17,WORD,1019,17 +LTP093,4,17,WORD,1155,18 +LTP093,4,17,WORD,1021,19 +LTP093,4,17,WORD,900,20 +LTP093,4,17,WORD,661,21 +LTP093,4,17,WORD,871,22 +LTP093,4,17,WORD,1329,23 +LTP093,4,17,WORD,1625,24 +LTP093,4,17,REC_WORD,1329,23 +LTP093,4,17,REC_WORD,1625,24 +LTP093,4,17,REC_WORD,900,20 +LTP093,4,17,REC_WORD,1021,19 +LTP093,4,17,REC_WORD,1155,18 +LTP093,4,17,REC_WORD,194,1 +LTP093,4,17,REC_WORD,429,2 +LTP093,4,17,REC_WORD,1493,3 +LTP093,4,17,REC_WORD,731,8 +LTP093,4,17,REC_WORD,604,9 +LTP093,4,17,REC_WORD,1199,4 +LTP093,4,18,WORD,24,1 +LTP093,4,18,WORD,1261,2 +LTP093,4,18,WORD,1051,3 +LTP093,4,18,WORD,1066,4 +LTP093,4,18,WORD,492,5 +LTP093,4,18,WORD,692,6 +LTP093,4,18,WORD,1448,7 +LTP093,4,18,WORD,1170,8 +LTP093,4,18,WORD,713,9 +LTP093,4,18,WORD,1203,10 +LTP093,4,18,WORD,1123,11 +LTP093,4,18,WORD,313,12 +LTP093,4,18,WORD,606,13 +LTP093,4,18,WORD,378,14 +LTP093,4,18,WORD,476,15 +LTP093,4,18,WORD,675,16 +LTP093,4,18,WORD,763,17 +LTP093,4,18,WORD,1488,18 +LTP093,4,18,WORD,570,19 +LTP093,4,18,WORD,249,20 +LTP093,4,18,WORD,1132,21 +LTP093,4,18,WORD,292,22 +LTP093,4,18,WORD,618,23 +LTP093,4,18,WORD,746,24 +LTP093,4,18,REC_WORD,292,22 +LTP093,4,18,REC_WORD,618,23 +LTP093,4,18,REC_WORD,746,24 +LTP093,4,18,REC_WORD,1066,4 +LTP093,4,18,REC_WORD,492,5 +LTP093,4,18,REC_WORD,692,6 +LTP093,4,18,REC_WORD,606,13 +LTP093,4,18,REC_WORD,378,14 +LTP093,4,18,REC_WORD,476,15 +LTP093,4,18,REC_WORD,1203,10 +LTP093,4,18,REC_WORD,1123,11 +LTP093,4,18,REC_WORD,313,12 +LTP093,4,19,WORD,988,1 +LTP093,4,19,WORD,561,2 +LTP093,4,19,WORD,610,3 +LTP093,4,19,WORD,1032,4 +LTP093,4,19,WORD,982,5 +LTP093,4,19,WORD,1557,6 +LTP093,4,19,WORD,1024,7 +LTP093,4,19,WORD,1496,8 +LTP093,4,19,WORD,401,9 +LTP093,4,19,WORD,870,10 +LTP093,4,19,WORD,1330,11 +LTP093,4,19,WORD,1065,12 +LTP093,4,19,WORD,341,13 +LTP093,4,19,WORD,1215,14 +LTP093,4,19,WORD,1092,15 +LTP093,4,19,WORD,1245,16 +LTP093,4,19,WORD,654,17 +LTP093,4,19,WORD,67,18 +LTP093,4,19,WORD,1079,19 +LTP093,4,19,WORD,1581,20 +LTP093,4,19,WORD,689,21 +LTP093,4,19,WORD,628,22 +LTP093,4,19,WORD,809,23 +LTP093,4,19,WORD,1626,24 +LTP093,4,19,REC_WORD,628,22 +LTP093,4,19,REC_WORD,809,23 +LTP093,4,19,REC_WORD,1626,24 +LTP093,4,19,REC_WORD,1079,19 +LTP093,4,19,REC_WORD,1581,20 +LTP093,4,19,REC_WORD,689,21 +LTP093,4,19,REC_WORD,654,17 +LTP093,4,19,REC_WORD,67,18 +LTP093,4,20,WORD,198,1 +LTP093,4,20,WORD,1524,2 +LTP093,4,20,WORD,495,3 +LTP093,4,20,WORD,691,4 +LTP093,4,20,WORD,1250,5 +LTP093,4,20,WORD,299,6 +LTP093,4,20,WORD,843,7 +LTP093,4,20,WORD,467,8 +LTP093,4,20,WORD,1183,9 +LTP093,4,20,WORD,1461,10 +LTP093,4,20,WORD,431,11 +LTP093,4,20,WORD,601,12 +LTP093,4,20,WORD,1530,13 +LTP093,4,20,WORD,940,14 +LTP093,4,20,WORD,64,15 +LTP093,4,20,WORD,737,16 +LTP093,4,20,WORD,1272,17 +LTP093,4,20,WORD,584,18 +LTP093,4,20,WORD,761,19 +LTP093,4,20,WORD,1219,20 +LTP093,4,20,WORD,328,21 +LTP093,4,20,WORD,1620,22 +LTP093,4,20,WORD,1093,23 +LTP093,4,20,WORD,1049,24 +LTP093,4,20,REC_WORD,1219,20 +LTP093,4,20,REC_WORD,328,21 +LTP093,4,20,REC_WORD,1620,22 +LTP093,4,20,REC_WORD,940,14 +LTP093,4,20,REC_WORD,64,15 +LTP093,4,20,REC_WORD,737,16 +LTP093,4,20,REC_WORD,299,6 +LTP093,4,20,REC_WORD,691,4 +LTP093,4,20,REC_WORD,1250,5 +LTP093,4,21,WORD,745,1 +LTP093,4,21,WORD,1440,2 +LTP093,4,21,WORD,1143,3 +LTP093,4,21,WORD,372,4 +LTP093,4,21,WORD,1200,5 +LTP093,4,21,WORD,1227,6 +LTP093,4,21,WORD,1555,7 +LTP093,4,21,WORD,1111,8 +LTP093,4,21,WORD,1373,9 +LTP093,4,21,WORD,1017,10 +LTP093,4,21,WORD,162,11 +LTP093,4,21,WORD,600,12 +LTP093,4,21,WORD,392,13 +LTP093,4,21,WORD,807,14 +LTP093,4,21,WORD,83,15 +LTP093,4,21,WORD,682,16 +LTP093,4,21,WORD,1221,17 +LTP093,4,21,WORD,769,18 +LTP093,4,21,WORD,91,19 +LTP093,4,21,WORD,1532,20 +LTP093,4,21,WORD,846,21 +LTP093,4,21,WORD,1609,22 +LTP093,4,21,WORD,439,23 +LTP093,4,21,WORD,1355,24 +LTP093,4,21,REC_WORD,1609,22 +LTP093,4,21,REC_WORD,439,23 +LTP093,4,21,REC_WORD,1355,24 +LTP093,4,21,REC_WORD,91,19 +LTP093,4,21,REC_WORD,1532,20 +LTP093,4,21,REC_WORD,846,21 +LTP093,4,21,REC_WORD,1017,10 +LTP093,4,21,REC_WORD,162,11 +LTP093,4,21,REC_WORD,600,12 +LTP093,4,21,REC_WORD,392,13 +LTP093,4,21,REC_WORD,807,14 +LTP093,4,21,REC_WORD,83,15 +LTP093,4,21,REC_WORD,1555,7 +LTP093,4,21,REC_WORD,1111,8 +LTP093,4,21,REC_WORD,1373,9 +LTP093,4,21,REC_WORD,372,4 +LTP093,4,21,REC_WORD,1200,5 +LTP093,4,21,REC_WORD,1227,6 +LTP093,4,21,REC_WORD,745,1 +LTP093,4,21,REC_WORD,1440,2 +LTP093,4,21,REC_WORD,1143,3 +LTP093,4,22,WORD,614,1 +LTP093,4,22,WORD,497,2 +LTP093,4,22,WORD,437,3 +LTP093,4,22,WORD,1606,4 +LTP093,4,22,WORD,834,5 +LTP093,4,22,WORD,989,6 +LTP093,4,22,WORD,794,7 +LTP093,4,22,WORD,567,8 +LTP093,4,22,WORD,660,9 +LTP093,4,22,WORD,666,10 +LTP093,4,22,WORD,1400,11 +LTP093,4,22,WORD,494,12 +LTP093,4,22,WORD,1546,13 +LTP093,4,22,WORD,1512,14 +LTP093,4,22,WORD,696,15 +LTP093,4,22,WORD,714,16 +LTP093,4,22,WORD,840,17 +LTP093,4,22,WORD,488,18 +LTP093,4,22,WORD,283,19 +LTP093,4,22,WORD,39,20 +LTP093,4,22,WORD,1172,21 +LTP093,4,22,WORD,573,22 +LTP093,4,22,WORD,578,23 +LTP093,4,22,WORD,1282,24 +LTP093,4,22,REC_WORD,573,22 +LTP093,4,22,REC_WORD,578,23 +LTP093,4,22,REC_WORD,1282,24 +LTP093,4,22,REC_WORD,283,19 +LTP093,4,22,REC_WORD,39,20 +LTP093,4,22,REC_WORD,1172,21 +LTP093,4,23,WORD,166,1 +LTP093,4,23,WORD,159,2 +LTP093,4,23,WORD,812,3 +LTP093,4,23,WORD,827,4 +LTP093,4,23,WORD,726,5 +LTP093,4,23,WORD,145,6 +LTP093,4,23,WORD,1002,7 +LTP093,4,23,WORD,724,8 +LTP093,4,23,WORD,1280,9 +LTP093,4,23,WORD,1326,10 +LTP093,4,23,WORD,1303,11 +LTP093,4,23,WORD,1536,12 +LTP093,4,23,WORD,131,13 +LTP093,4,23,WORD,509,14 +LTP093,4,23,WORD,1328,15 +LTP093,4,23,WORD,879,16 +LTP093,4,23,WORD,707,17 +LTP093,4,23,WORD,413,18 +LTP093,4,23,WORD,953,19 +LTP093,4,23,WORD,699,20 +LTP093,4,23,WORD,53,21 +LTP093,4,23,WORD,164,22 +LTP093,4,23,WORD,1275,23 +LTP093,4,23,WORD,142,24 +LTP093,4,23,REC_WORD,164,22 +LTP093,4,23,REC_WORD,1275,23 +LTP093,4,23,REC_WORD,142,24 +LTP093,4,23,REC_WORD,953,19 +LTP093,4,23,REC_WORD,699,20 +LTP093,4,23,REC_WORD,53,21 +LTP093,4,23,REC_WORD,879,16 +LTP093,4,23,REC_WORD,413,18 +LTP093,4,23,REC_WORD,707,17 +LTP093,4,23,REC_WORD,827,4 +LTP093,4,23,REC_WORD,726,5 +LTP093,4,23,REC_WORD,145,6 +LTP093,4,23,REC_WORD,1002,7 +LTP093,4,23,REC_WORD,724,8 +LTP093,4,23,REC_WORD,1280,9 +LTP093,4,23,REC_WORD,131,13 +LTP093,4,23,REC_WORD,509,14 +LTP093,4,23,REC_WORD,1328,15 +LTP093,4,24,WORD,935,1 +LTP093,4,24,WORD,541,2 +LTP093,4,24,WORD,1436,3 +LTP093,4,24,WORD,442,4 +LTP093,4,24,WORD,1622,5 +LTP093,4,24,WORD,947,6 +LTP093,4,24,WORD,1258,7 +LTP093,4,24,WORD,1385,8 +LTP093,4,24,WORD,1229,9 +LTP093,4,24,WORD,1349,10 +LTP093,4,24,WORD,885,11 +LTP093,4,24,WORD,63,12 +LTP093,4,24,WORD,75,13 +LTP093,4,24,WORD,1341,14 +LTP093,4,24,WORD,937,15 +LTP093,4,24,WORD,403,16 +LTP093,4,24,WORD,624,17 +LTP093,4,24,WORD,82,18 +LTP093,4,24,WORD,119,19 +LTP093,4,24,WORD,778,20 +LTP093,4,24,WORD,1460,21 +LTP093,4,24,WORD,343,22 +LTP093,4,24,WORD,1148,23 +LTP093,4,24,WORD,1384,24 +LTP093,4,24,REC_WORD,343,22 +LTP093,4,24,REC_WORD,1148,23 +LTP093,4,24,REC_WORD,1384,24 +LTP093,4,24,REC_WORD,1349,10 +LTP093,4,24,REC_WORD,885,11 +LTP093,4,24,REC_WORD,63,12 +LTP093,4,24,REC_WORD,1341,14 +LTP093,4,24,REC_WORD,75,13 +LTP093,4,24,REC_WORD,442,4 +LTP093,4,24,REC_WORD,1622,5 +LTP093,4,24,REC_WORD,947,6 +LTP093,4,24,REC_WORD,541,2 +LTP093,4,24,REC_WORD,935,1 +LTP093,4,24,REC_WORD,1436,3 diff --git a/tests/data/ltpfr2_golden.npz b/tests/data/ltpfr2_golden.npz new file mode 100644 index 0000000000000000000000000000000000000000..0f0f09d619f0b1d7d6843454c1e644d4d11a9024 GIT binary patch literal 114244 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 ``list`` (matching the lab's own - loader in subjective_item_memorability/load_behavioral_data.py). -- encoding events are ``WORD``; retrieval events are ``REC_WORD``. - -These are gated behind :func:`ltpfr2_available` so the suite skips cleanly off -rhino or without cmlreaders installed. Data are loaded live (never committed). +``item_num`` is the 1-based wordpool id (the ``itemno`` pybeh_pd uses); encoding +events are ``WORD`` and retrieval events are ``REC_WORD``. To refresh the fixture +from rhino, re-run ``tests/data/_regenerate_ltpfr2.py`` (needs cmlreaders). """ from __future__ import annotations import functools import os -RHINO_ROOT = "/" -LTPFR2_PROTOCOL_DIR = "/protocols/ltp" +import numpy as np +import pandas as pd + +_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") +FIXTURE_CSV = os.path.join(_DATA_DIR, "ltpfr2_5sessions.csv") +GOLDEN_NPZ = os.path.join(_DATA_DIR, "ltpfr2_golden.npz") + + +@functools.lru_cache(maxsize=1) +def load_ltpfr2_long() -> pd.DataFrame: + """Load the committed 5-session ltpFR2 fixture as a long DataFrame.""" + return pd.read_csv(FIXTURE_CSV) -def ltpfr2_available() -> bool: - """True iff cmlreaders is importable and the ltp protocol tree is mounted.""" - if not os.path.isdir(LTPFR2_PROTOCOL_DIR): - return False - try: - import cmlreaders # noqa: F401 - except Exception: - return False - return True +@functools.lru_cache(maxsize=1) +def load_ltpfr2_golden() -> dict: + """Load the frozen pybeh_pd outputs captured on the fixture.""" + with np.load(GOLDEN_NPZ) as data: + return {k: data[k] for k in data.files} -@functools.lru_cache(maxsize=8) -def load_ltpfr2_long(subject: str = "LTP093", n_sessions: int = 5): - """Load the first ``n_sessions`` of one ltpFR2 subject as a long DataFrame. +ITEMNO = "item_num" - Cached so the (slow) rhino read happens once per (subject, n_sessions). - Returns a DataFrame with columns - [subject, session, list, type, item_num, serialpos], containing only WORD - and REC_WORD events. Session 23 (a different wordpool) is skipped. + +def capture_outputs(df) -> dict: + """Every pybeh_pd analysis applicable to plain free-recall events, as a + {name: float-ndarray} dict. Single source of truth shared by the golden + regeneration script and the regression test, so they cannot drift. + + Semantic CRP / distance-factor are intentionally absent: ltpFR2 events carry + no semantic feature space (those are locked on the synthetic suite instead). """ - import cmlreaders as cml - import pandas as pd - - idx = cml.get_data_index("ltp", rootdir=RHINO_ROOT).query( - "experiment == 'ltpFR2'") - rows = ( - idx.query("subject == @subject and session != 23") - .sort_values("session") - .head(n_sessions) - ) - keep = ["subject", "session", "list", "type", "item_num", "serialpos"] - frames = [] - for r in rows.itertuples(): - ev = cml.CMLReader( - subject=r.subject, session=int(r.session), - experiment="ltpFR2", rootdir=RHINO_ROOT, - ).load("events") - if "list" in ev.columns: - ev = ev.drop(columns="list") - ev = ev.rename(columns={"trial": "list"}) - ev = ev.query("type in ['WORD', 'REC_WORD']") - frames.append(ev[keep]) - return pd.concat(frames, ignore_index=True) + import pybeh_pd as pb + + def a(x): + return np.asarray(x, dtype=float) + + out = {} + pres, rec, recalls = pb.get_all_matrices(df, itemno_column=ITEMNO) + out["pres_itemnos"] = a(pres) + out["rec_itemnos"] = a(rec) + out["recalls"] = a(recalls) + out["poss_recalls"] = a(pb.make_poss_recalls_matrix(pres)) + out["clean_mask"] = a(pb.make_clean_recalls_mask2d(recalls)) + subs = ["_"] * pres.shape[0] + out["crp_matrix"] = a(pb.crp(recalls=recalls, subjects=subs, + listLength=pres.shape[1], lag_num=5)) + out["temp_fact_matrix"] = a(pb.temp_fact(recalls=recalls, subjects=subs, + listLength=pres.shape[1])) + crp = pb.pd_crp(df, lag_num=5, itemno_column=ITEMNO).sort_values("lag") + out["pd_crp_prob"] = a(crp["prob"].values) + out["pd_crp_lag"] = a(crp["lag"].values) + out["pd_min_crp_prob"] = a(pb.pd_min_crp(df, lag_num=5, itemno_column=ITEMNO) + .sort_values("lag")["prob"].values) + out["pd_temp_fact"] = a([pb.pd_temp_fact(df, itemno_column=ITEMNO)]) + out["pd_min_temp_fact_r2"] = a([pb.pd_min_temp_fact(df, itemno_column=ITEMNO, + max_n_reps=2)]) + sess_ids = sorted(df["session"].unique()) + out["session_ids"] = a(sess_ids) + out["pd_temp_fact_per_session"] = a( + [pb.pd_temp_fact(df[df["session"] == s], itemno_column=ITEMNO) + for s in sess_ids]) + out["pd_crp_prob_per_session"] = a( + [pb.pd_crp(df[df["session"] == s], lag_num=5, itemno_column=ITEMNO) + .sort_values("lag")["prob"].values for s in sess_ids]) + return out diff --git a/tests/test_real_data.py b/tests/test_real_data.py index 8f726ca..ada2b8e 100644 --- a/tests/test_real_data.py +++ b/tests/test_real_data.py @@ -1,129 +1,129 @@ -"""Real-data integration tests on 5 ltpFR2 sessions (loaded via cmlreaders). +"""Real-data integration tests on 5 ltpFR2 sessions (committed fixture). -These run the actual ``pybeh_pd`` pipeline on real scalp-EEG free-recall data and -assert the well-established empirical signatures of free recall — the *temporal -contiguity effect* (Kahana 1996) and above-chance *temporal clustering* (Polyn, -Norman & Kahana 2009). They also confirm the synthetic fixture factory mirrors the -real event schema, which is what licenses the synthetic-data unit tests elsewhere. +Runs the actual ``pybeh_pd`` pipeline on real scalp-EEG free-recall data and +asserts both (a) the well-established empirical signatures of free recall — the +*temporal contiguity effect* (Kahana 1996) and above-chance *temporal clustering* +(Polyn, Norman & Kahana 2009) — and (b) that the outputs exactly match the frozen +golden values captured on this fixture, so the real-data behavior is locked too. -Skipped automatically off rhino / without cmlreaders. Data are loaded live and -never committed. +Data + golden live in tests/data/ and are loaded from disk; neither cmlreaders nor +rhino is required. The synthetic fixture factory is also checked against the real +event schema, which is what licenses the synthetic-data unit tests elsewhere. """ from __future__ import annotations import numpy as np + import pytest import pybeh_pd as pb -from real_data import ltpfr2_available, load_ltpfr2_long +from real_data import load_ltpfr2_long, load_ltpfr2_golden, capture_outputs from factories import make_experiment -pytestmark = [ - pytest.mark.needs_data, - pytest.mark.integration, - pytest.mark.skipif(not ltpfr2_available(), - reason="ltpFR2 data / cmlreaders not available"), -] - ITEMNO = "item_num" LIST_LENGTH = 24 # ltpFR2 lists are 24 items +RTOL, ATOL = 1e-9, 1e-12 -@pytest.fixture(scope="module") -def ltpfr2(): - return load_ltpfr2_long(subject="LTP093", n_sessions=5) - +# --- sanity: 5 sessions of valid free-recall data --------------------------- -# --- sanity: we actually loaded 5 sessions of valid free-recall data --------- - -def test_loaded_five_sessions(ltpfr2): - assert ltpfr2["session"].nunique() == 5 - assert set(ltpfr2["type"].unique()) == {"WORD", "REC_WORD"} - # 24 lists/session x 24 items = 576 study events per session - study = ltpfr2.query("type == 'WORD'") - per_sess = study.groupby("session")["list"].nunique() - assert (per_sess == 24).all() +def test_loaded_five_sessions(): + df = load_ltpfr2_long() + assert df["session"].nunique() == 5 + assert set(df["type"].unique()) == {"WORD", "REC_WORD"} + study = df.query("type == 'WORD'") + assert (study.groupby("session")["list"].nunique() == 24).all() assert (study.groupby(["session", "list"]).size() == LIST_LENGTH).all() # --- the synthetic factory mirrors the real schema (validates fixtures) ------ -def test_synthetic_fixture_mirrors_real_schema(ltpfr2): +def test_synthetic_fixture_mirrors_real_schema(): + df = load_ltpfr2_long() syn = make_experiment(seed=0)["events"] for col in ["subject", "session", "list", "type"]: - assert col in ltpfr2.columns and col in syn.columns - # both encode presentations as WORD and recalls as REC_WORD + assert col in df.columns and col in syn.columns assert {"WORD", "REC_WORD"}.issubset(set(syn["type"].unique())) - assert {"WORD", "REC_WORD"} == set(ltpfr2["type"].unique()) - # both carry a 1-based integer item id and a serialpos - assert (ltpfr2.query("type=='WORD'")[ITEMNO] > 0).all() + assert {"WORD", "REC_WORD"} == set(df["type"].unique()) + assert (df.query("type=='WORD'")[ITEMNO] > 0).all() assert (syn.query("type=='WORD'")["itemno"] > 0).all() -# --- lag-CRP: temporal contiguity effect ------------------------------------- +# --- lag-CRP: temporal contiguity effect (properties) ----------------------- -def test_pd_crp_contiguity_and_asymmetry(ltpfr2): - crp = pb.pd_crp(ltpfr2, lag_num=5, itemno_column=ITEMNO).set_index("lag") +def test_pd_crp_contiguity_and_asymmetry(): + crp = pb.pd_crp(load_ltpfr2_long(), lag_num=5, itemno_column=ITEMNO).set_index("lag") prob = crp["prob"] - # lag 0 is undefined - assert np.isnan(prob.loc[0]) - # all probabilities are valid + assert np.isnan(prob.loc[0]) # lag 0 undefined valid = prob.drop(index=0) - assert ((valid >= 0) & (valid <= 1)).all() - # contiguity: adjacent transitions dominate distant ones - assert prob.loc[1] > prob.loc[5] - assert prob.loc[-1] > prob.loc[-5] - # +1 is the single most likely transition - assert prob.loc[1] == valid.max() - # forward asymmetry: forward adjacency beats backward adjacency - assert prob.loc[1] > prob.loc[-1] - - -# --- temporal clustering factor: above chance -------------------------------- - -def test_pd_crp_matches_per_subject_decomposition(ltpfr2): - """The canonical usage (FR1_analyses.ipynb cell 10) is - ``events.groupby('subject').apply(pb.pd_crp, itemno_column='item_num')``, - i.e. pd_crp applied independently to each subject's events. Confirm the direct - call on a single subject's frame equals that per-subject decomposition. - - NB the literal ``groupby(...).apply(...)`` idiom from the notebooks breaks on - pandas >= 3 (the grouping column 'subject', which pd_crp needs via - ``list_index``, is now dropped from the applied frame). We express the - decomposition by explicit slicing so the equivalence holds on pandas 2 and 3; - the notebook idiom itself is tracked as a pandas-3 compat item in bug_report.md. - """ - direct = pb.pd_crp(ltpfr2, itemno_column=ITEMNO).sort_values("lag")["prob"].values + assert ((valid >= 0) & (valid <= 1)).all() # valid probabilities + assert prob.loc[1] > prob.loc[5] # forward contiguity + assert prob.loc[-1] > prob.loc[-5] # backward contiguity + assert prob.loc[1] == valid.max() # +1 most likely + assert prob.loc[1] > prob.loc[-1] # forward asymmetry + + +def test_pd_crp_matches_per_subject_decomposition(): + """Canonical usage (FR1_analyses.ipynb cell 10) is pd_crp applied per subject: + ``events.groupby('subject').apply(pb.pd_crp, itemno_column='item_num')``. For + one subject the direct call must equal that decomposition. (The literal + groupby-apply idiom itself breaks on pandas 3 — grouping column dropped — see + bug_report.md; we express the decomposition by explicit slicing here.)""" + df = load_ltpfr2_long() + direct = pb.pd_crp(df, itemno_column=ITEMNO).sort_values("lag")["prob"].values per_subject = [ pb.pd_crp(g, itemno_column=ITEMNO).sort_values("lag")["prob"].values - for _, g in ltpfr2.groupby("subject") + for _, g in df.groupby("subject") ] - assert len(per_subject) == 1 # this fixture is one subject + assert len(per_subject) == 1 assert np.allclose(direct, per_subject[0], equal_nan=True) -def test_pd_temp_fact_above_chance(ltpfr2): - tf = pb.pd_temp_fact(ltpfr2, itemno_column=ITEMNO) - # chance is 0.5; ltpFR2 shows strong clustering +# --- temporal clustering factor: above chance (properties) ------------------ + +def test_pd_temp_fact_above_chance(): + tf = pb.pd_temp_fact(load_ltpfr2_long(), itemno_column=ITEMNO) assert 0.5 < tf <= 1.0 assert tf > 0.6 -def test_temp_fact_per_session_above_chance(ltpfr2): - for sess, g in ltpfr2.groupby("session"): +def test_temp_fact_per_session_above_chance(): + df = load_ltpfr2_long() + for sess, g in df.groupby("session"): tf = pb.pd_temp_fact(g, itemno_column=ITEMNO) assert 0.5 < tf <= 1.0, f"session {sess}: temp_fact={tf}" # --- matrix builders produce valid serial positions on real data ------------ -def test_get_all_matrices_valid_serialpos(ltpfr2): - pres, rec, recalls = pb.get_all_matrices(ltpfr2, itemno_column=ITEMNO) +def test_get_all_matrices_valid_serialpos(): + pres, rec, recalls = pb.get_all_matrices(load_ltpfr2_long(), itemno_column=ITEMNO) assert pres.shape[1] == LIST_LENGTH assert recalls.shape == rec.shape - # recalls entries are padding (0), intrusion (-1), or a serial position 1..24 - uniq = np.unique(recalls) - assert uniq.min() >= -1 + assert recalls.min() >= -1 assert recalls.max() <= LIST_LENGTH correct = recalls[recalls > 0] assert ((correct >= 1) & (correct <= LIST_LENGTH)).all() + + +# --- behavior lock: every applicable analysis matches frozen golden ---------- +# capture_outputs() is the single source of truth shared with the golden +# regeneration script, so this checks the full real-data output set, not a subset. + +GOLDEN_KEYS = sorted(load_ltpfr2_golden().keys()) + + +def test_golden_case_set_is_complete(): + """Live capture and the committed golden must cover the same analyses.""" + live = capture_outputs(load_ltpfr2_long()) + assert set(live) == set(load_ltpfr2_golden()) + + +@pytest.mark.parametrize("name", GOLDEN_KEYS) +def test_real_data_output_matches_golden(name): + live = capture_outputs(load_ltpfr2_long()) + g = load_ltpfr2_golden() + x = np.asarray(live[name], dtype=float) + assert x.shape == g[name].shape, f"{name}: {x.shape} != {g[name].shape}" + assert np.allclose(x, g[name], rtol=RTOL, atol=ATOL, equal_nan=True), ( + f"{name} diverged from golden") From ec112b1c0fde9563185398b4e657cf0fbf619eef Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 02:18:19 +0000 Subject: [PATCH 10/15] build: convert to installable src/ package with pyproject (hatchling) Restructure the flat pybeh_pd.py + pybeh_copy.py into a proper package: src/pybeh_pd/__init__.py - re-exports the public API (unchanged surface) src/pybeh_pd/_core.py - former pybeh_pd.py (intra-package import of vendored) src/pybeh_pd/_pybeh.py - former pybeh_copy.py (vendored pybeh subset) The implicit 'from pybeh_copy import ...' becomes 'from ._pybeh import ...', fixing the import that previously only worked with the repo root on sys.path. Adds a hatchling pyproject.toml (pip install / editable / wheel + sdist all verified) and wires an editable self-install into the pixi envs; pytest config moves from pytest.ini into pyproject. Behavior-preserving: 216 tests pass on numpy 1.24/pandas 2.3 and numpy 2.4/pandas 3.0; clean-venv wheel install exposes the same 36 public names. --- conftest.py | 16 +- pixi.lock | 210 ++++++++++++++++++++++++ pixi.toml | 11 +- pyproject.toml | 49 ++++++ pytest.ini | 10 -- src/pybeh_pd/__init__.py | 15 ++ pybeh_pd.py => src/pybeh_pd/_core.py | 2 +- pybeh_copy.py => src/pybeh_pd/_pybeh.py | 0 tests/data/_regenerate_ltpfr2.py | 4 +- tests/regression/cases.py | 4 +- tests/regression/test_regression.py | 4 - tests/test_clustering.py | 21 +-- 12 files changed, 306 insertions(+), 40 deletions(-) create mode 100644 pyproject.toml delete mode 100644 pytest.ini create mode 100644 src/pybeh_pd/__init__.py rename pybeh_pd.py => src/pybeh_pd/_core.py (99%) rename pybeh_copy.py => src/pybeh_pd/_pybeh.py (100%) diff --git a/conftest.py b/conftest.py index 927c977..5dc561d 100644 --- a/conftest.py +++ b/conftest.py @@ -1,7 +1,15 @@ """Pytest configuration. -The presence of this file at the repo root makes pytest add the repo root to -``sys.path``, so the top-level ``pybeh_pd`` / ``pybeh_copy`` modules import during -testing without an install. This is intentional for the pre-packaging phases; once -the package is installed (editable), the import resolves the same way. +Puts the ``src/`` layout package and the ``tests/`` helper dir on ``sys.path`` so +``import pybeh_pd`` and ``from factories import ...`` / ``from real_data import +...`` resolve during testing without requiring an install. When the package is +also editable-installed (the pixi envs), the import resolves to the same ``src/`` +tree, so there is no conflict. """ +import os +import sys + +_ROOT = os.path.dirname(os.path.abspath(__file__)) +for _p in (os.path.join(_ROOT, "src"), os.path.join(_ROOT, "tests")): + if _p not in sys.path: + sys.path.insert(0, _p) diff --git a/pixi.lock b/pixi.lock index 88aef25..e659a3f 100644 --- a/pixi.lock +++ b/pixi.lock @@ -7,6 +7,8 @@ environments: default: channels: - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda @@ -53,6 +55,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - pypi: . osx-64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -96,6 +99,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - pypi: . osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -139,9 +143,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - pypi: . py311: channels: - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda @@ -190,6 +197,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - pypi: . osx-64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -232,6 +240,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - pypi: . osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -274,9 +283,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - pypi: . py312: channels: - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda @@ -325,6 +337,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - pypi: . osx-64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -367,6 +380,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - pypi: . osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -409,9 +423,12 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - pypi: . py313: channels: - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple packages: linux-64: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda @@ -458,6 +475,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - pypi: . osx-64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -501,6 +519,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda + - pypi: . osx-arm64: - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -544,6 +563,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda + - pypi: . packages: - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda build_number: 20 @@ -556,6 +576,7 @@ packages: - openmp_impl <0.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 28948 timestamp: 1770939786096 - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda @@ -566,6 +587,7 @@ packages: - libgcc >=14 license: bzip2-1.0.6 license_family: BSD + purls: [] size: 260182 timestamp: 1771350215188 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py311h3778330_0.conda @@ -579,6 +601,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 399156 timestamp: 1779838054673 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py312h8a5da7c_0.conda @@ -592,6 +616,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 389696 timestamp: 1779838017522 - conda: https://conda.anaconda.org/conda-forge/linux-64/coverage-7.14.1-py313h3dea7bd_0.conda @@ -605,6 +631,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 396489 timestamp: 1779837909103 - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda @@ -617,6 +645,7 @@ packages: - binutils_impl_linux-64 2.45.1 license: GPL-3.0-only license_family: GPL + purls: [] size: 728002 timestamp: 1774197446916 - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-8_h4a7cf45_openblas.conda @@ -634,6 +663,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18804 timestamp: 1779859100675 - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-8_h0358290_openblas.conda @@ -648,6 +678,7 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18778 timestamp: 1779859107964 - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_0.conda @@ -660,6 +691,7 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT + purls: [] size: 77294 timestamp: 1779278686680 - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda @@ -670,6 +702,7 @@ packages: - libgcc >=14 license: MIT license_family: MIT + purls: [] size: 58592 timestamp: 1769456073053 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda @@ -683,6 +716,7 @@ packages: - libgomp 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 1041084 timestamp: 1778269013026 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_19.conda @@ -692,6 +726,7 @@ packages: - libgcc 15.2.0 he0feb66_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 27694 timestamp: 1778269016987 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_19.conda @@ -703,6 +738,7 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 27655 timestamp: 1778269042954 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_19.conda @@ -715,6 +751,7 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 2483673 timestamp: 1778269025089 - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda @@ -724,6 +761,7 @@ packages: - __glibc >=2.17,<3.0.a0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 603817 timestamp: 1778268942614 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-8_h47877c9_openblas.conda @@ -738,6 +776,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18790 timestamp: 1779859115086 - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda @@ -749,6 +788,7 @@ packages: constrains: - xz 5.8.3.* license: 0BSD + purls: [] size: 113478 timestamp: 1775825492909 - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda @@ -759,6 +799,7 @@ packages: - libgcc >=14 license: BSD-2-Clause license_family: BSD + purls: [] size: 92400 timestamp: 1769482286018 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda @@ -769,6 +810,7 @@ packages: - libgcc >=13 license: LGPL-2.1-only license_family: GPL + purls: [] size: 33731 timestamp: 1750274110928 - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.33-pthreads_h94d23a6_0.conda @@ -783,6 +825,7 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 5931919 timestamp: 1776993658641 - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda @@ -793,6 +836,7 @@ packages: - libgcc >=14 - libzlib >=1.3.2,<2.0a0 license: blessing + purls: [] size: 957849 timestamp: 1780574429573 - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda @@ -805,6 +849,7 @@ packages: - libstdcxx-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 5852044 timestamp: 1778269036376 - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda @@ -815,6 +860,7 @@ packages: - libgcc >=14 license: BSD-3-Clause license_family: BSD + purls: [] size: 40163 timestamp: 1779118517630 - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda @@ -823,6 +869,7 @@ packages: depends: - libgcc-ng >=12 license: LGPL-2.1-or-later + purls: [] size: 100393 timestamp: 1702724383534 - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda @@ -834,6 +881,7 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other + purls: [] size: 63629 timestamp: 1774072609062 - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda @@ -843,6 +891,7 @@ packages: - __glibc >=2.17,<3.0.a0 - libgcc >=14 license: X11 AND BSD-3-Clause + purls: [] size: 918956 timestamp: 1777422145199 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py311h2e04523_0.conda @@ -861,6 +910,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping size: 9389525 timestamp: 1779169198155 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py312h33ff503_0.conda @@ -879,6 +930,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping size: 8759520 timestamp: 1779169200325 - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.4.6-py313hf6604e3_0.conda @@ -897,6 +950,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping size: 8864096 timestamp: 1779169199037 - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.2-h35e630c_0.conda @@ -908,6 +963,7 @@ packages: - libgcc >=14 license: Apache-2.0 license_family: Apache + purls: [] size: 3167099 timestamp: 1775587756857 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda @@ -963,6 +1019,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=compressed-mapping size: 15174736 timestamp: 1778602614189 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda @@ -1018,6 +1076,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=compressed-mapping size: 14872605 timestamp: 1778602625175 - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py313hbfd7664_0.conda @@ -1073,6 +1133,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=compressed-mapping size: 15001668 timestamp: 1778602610159 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda @@ -1099,6 +1161,7 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 + purls: [] size: 30949404 timestamp: 1772730362552 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda @@ -1125,6 +1188,7 @@ packages: constrains: - python_abi 3.12.* *_cp312 license: Python-2.0 + purls: [] size: 31608571 timestamp: 1772730708989 - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda @@ -1150,6 +1214,7 @@ packages: - tk >=8.6.13,<8.7.0a0 - tzdata license: Python-2.0 + purls: [] size: 37358322 timestamp: 1775614712638 python_site_packages_path: lib/python3.13/site-packages @@ -1162,6 +1227,7 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL + purls: [] size: 345073 timestamp: 1765813471974 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda @@ -1183,6 +1249,8 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 17303931 timestamp: 1779874783665 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py312h54fa4ab_1.conda @@ -1204,6 +1272,8 @@ packages: - python_abi 3.12.* *_cp312 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 16828243 timestamp: 1779874781187 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_1.conda @@ -1225,6 +1295,8 @@ packages: - python_abi 3.13.* *_cp313 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 17184702 timestamp: 1779874789436 - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda @@ -1238,6 +1310,7 @@ packages: - xorg-libx11 >=1.8.12,<2.0a0 license: TCL license_family: BSD + purls: [] size: 3301196 timestamp: 1769460227866 - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -1248,6 +1321,7 @@ packages: - libzlib >=1.3.1,<2.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 601375 timestamp: 1764777111296 - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda @@ -1256,6 +1330,7 @@ packages: depends: - __unix license: ISC + purls: [] size: 129868 timestamp: 1779289852439 - conda: https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda @@ -1265,6 +1340,8 @@ packages: - python >=3.9 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/colorama?source=hash-mapping size: 27011 timestamp: 1733218222191 - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda @@ -1274,6 +1351,8 @@ packages: - python >=3.10 - typing_extensions >=4.6.0 license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup?source=hash-mapping size: 21333 timestamp: 1763918099466 - conda: https://conda.anaconda.org/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda @@ -1283,6 +1362,8 @@ packages: - python >=3.10 license: MIT license_family: MIT + purls: + - pkg:pypi/iniconfig?source=hash-mapping size: 13387 timestamp: 1760831448842 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda @@ -1293,6 +1374,8 @@ packages: - python license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/packaging?source=hash-mapping size: 91574 timestamp: 1777103621679 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda @@ -1303,6 +1386,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/pluggy?source=hash-mapping size: 25877 timestamp: 1764896838868 - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda @@ -1312,6 +1397,8 @@ packages: - python >=3.10 license: BSD-2-Clause license_family: BSD + purls: + - pkg:pypi/pygments?source=hash-mapping size: 893031 timestamp: 1774796815820 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-9.0.3-pyhc364b38_1.conda @@ -1331,6 +1418,8 @@ packages: - pytest-faulthandler >=2 license: MIT license_family: MIT + purls: + - pkg:pypi/pytest?source=hash-mapping size: 299984 timestamp: 1775644472530 - conda: https://conda.anaconda.org/conda-forge/noarch/pytest-cov-7.1.0-pyhcf101f3_0.conda @@ -1344,6 +1433,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/pytest-cov?source=hash-mapping size: 29559 timestamp: 1774139250481 - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda @@ -1355,6 +1446,8 @@ packages: - python license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/python-dateutil?source=hash-mapping size: 233310 timestamp: 1751104122689 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda @@ -1365,6 +1458,7 @@ packages: - python 3.11.* *_cpython license: BSD-3-Clause license_family: BSD + purls: [] size: 7003 timestamp: 1752805919375 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda @@ -1375,6 +1469,7 @@ packages: - python 3.12.* *_cpython license: BSD-3-Clause license_family: BSD + purls: [] size: 6958 timestamp: 1752805918820 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda @@ -1385,6 +1480,7 @@ packages: - python 3.13.* *_cp313 license: BSD-3-Clause license_family: BSD + purls: [] size: 7002 timestamp: 1752805902938 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda @@ -1395,6 +1491,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/six?source=hash-mapping size: 18455 timestamp: 1753199211006 - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda @@ -1405,6 +1503,8 @@ packages: - python license: MIT license_family: MIT + purls: + - pkg:pypi/tomli?source=hash-mapping size: 21561 timestamp: 1774492402955 - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda @@ -1415,12 +1515,15 @@ packages: - python license: PSF-2.0 license_family: PSF + purls: + - pkg:pypi/typing-extensions?source=hash-mapping size: 51692 timestamp: 1756220668932 - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda sha256: 1d30098909076af33a35017eed6f2953af1c769e273a0626a04722ac4acaba3c md5: ad659d0a2b3e47e38d829aa8cad2d610 license: LicenseRef-Public-Domain + purls: [] size: 119135 timestamp: 1767016325805 - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda @@ -1431,6 +1534,7 @@ packages: - llvm-openmp >=9.0.1 license: BSD-3-Clause license_family: BSD + purls: [] size: 8328 timestamp: 1764092562779 - conda: https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h500dc9f_9.conda @@ -1440,6 +1544,7 @@ packages: - __osx >=10.13 license: bzip2-1.0.6 license_family: BSD + purls: [] size: 133427 timestamp: 1771350680709 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py311ha8ae342_0.conda @@ -1452,6 +1557,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 396933 timestamp: 1779838320779 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py312heb39f77_0.conda @@ -1464,6 +1571,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 388114 timestamp: 1779838145107 - conda: https://conda.anaconda.org/conda-forge/osx-64/coverage-7.14.1-py313h035b7d0_0.conda @@ -1476,6 +1585,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 395003 timestamp: 1779838290292 - conda: https://conda.anaconda.org/conda-forge/osx-64/icu-78.3-h25d91c4_0.conda @@ -1485,6 +1596,7 @@ packages: - __osx >=11.0 license: MIT license_family: MIT + purls: [] size: 12273764 timestamp: 1773822733780 - conda: https://conda.anaconda.org/conda-forge/osx-64/libblas-3.11.0-8_he492b99_openblas.conda @@ -1502,6 +1614,7 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 19048 timestamp: 1779860008916 - conda: https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.11.0-8_h9b27e0a_openblas.conda @@ -1516,6 +1629,7 @@ packages: - liblapack 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 19049 timestamp: 1779860025163 - conda: https://conda.anaconda.org/conda-forge/osx-64/libcxx-22.1.7-h19cb2f5_0.conda @@ -1525,6 +1639,7 @@ packages: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache + purls: [] size: 564939 timestamp: 1780442565078 - conda: https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.8.1-hcc62823_0.conda @@ -1536,6 +1651,7 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT + purls: [] size: 75654 timestamp: 1779279058576 - conda: https://conda.anaconda.org/conda-forge/osx-64/libffi-3.5.2-hd1f9c09_0.conda @@ -1545,6 +1661,7 @@ packages: - __osx >=10.13 license: MIT license_family: MIT + purls: [] size: 53583 timestamp: 1769456300951 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgcc-15.2.0-h08519bb_19.conda @@ -1557,6 +1674,7 @@ packages: - libgcc-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 424164 timestamp: 1778271183296 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran-15.2.0-h7e5c614_19.conda @@ -1568,6 +1686,7 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 139925 timestamp: 1778271458366 - conda: https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-15.2.0-hd16e46c_19.conda @@ -1579,6 +1698,7 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 1063687 timestamp: 1778271196574 - conda: https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.11.0-8_h859234e_openblas.conda @@ -1593,6 +1713,7 @@ packages: - blas 2.308 openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 19030 timestamp: 1779860046842 - conda: https://conda.anaconda.org/conda-forge/osx-64/liblzma-5.8.3-hbb4bfdb_0.conda @@ -1603,6 +1724,7 @@ packages: constrains: - xz 5.8.3.* license: 0BSD + purls: [] size: 105724 timestamp: 1775826029494 - conda: https://conda.anaconda.org/conda-forge/osx-64/libmpdec-4.0.0-hf3981d6_1.conda @@ -1612,6 +1734,7 @@ packages: - __osx >=10.13 license: BSD-2-Clause license_family: BSD + purls: [] size: 79899 timestamp: 1769482558610 - conda: https://conda.anaconda.org/conda-forge/osx-64/libopenblas-0.3.33-openmp_h9e49c7b_0.conda @@ -1626,6 +1749,7 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 6287889 timestamp: 1776996499823 - conda: https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.53.2-h8f8c405_0.conda @@ -1636,6 +1760,7 @@ packages: - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing + purls: [] size: 1010419 timestamp: 1780575011758 - conda: https://conda.anaconda.org/conda-forge/osx-64/libzlib-1.3.2-hbb4bfdb_2.conda @@ -1647,6 +1772,7 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other + purls: [] size: 59000 timestamp: 1774073052242 - conda: https://conda.anaconda.org/conda-forge/osx-64/llvm-openmp-22.1.7-h0d3cbff_0.conda @@ -1659,6 +1785,7 @@ packages: - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE + purls: [] size: 310879 timestamp: 1780456054580 - conda: https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.6-hcc0dc9a_0.conda @@ -1667,6 +1794,7 @@ packages: depends: - __osx >=11.0 license: X11 AND BSD-3-Clause + purls: [] size: 831711 timestamp: 1777423052277 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py311h2c4eb96_0.conda @@ -1684,6 +1812,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping size: 8593034 timestamp: 1779169256521 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py312h746d82c_0.conda @@ -1701,6 +1831,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping size: 7997002 timestamp: 1779782916096 - conda: https://conda.anaconda.org/conda-forge/osx-64/numpy-2.4.6-py313hb870fc3_0.conda @@ -1718,6 +1850,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping size: 8068573 timestamp: 1779169285266 - conda: https://conda.anaconda.org/conda-forge/osx-64/openssl-3.6.2-hc881268_0.conda @@ -1728,6 +1862,7 @@ packages: - ca-certificates license: Apache-2.0 license_family: Apache + purls: [] size: 2776564 timestamp: 1775589970694 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda @@ -1782,6 +1917,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14558446 timestamp: 1778602873120 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py312h8e27051_0.conda @@ -1836,6 +1973,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14170082 timestamp: 1778602746933 - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py313hfd25234_0.conda @@ -1890,6 +2029,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14290954 timestamp: 1778602759825 - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.15-ha9537fe_0_cpython.conda @@ -1911,6 +2052,7 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 + purls: [] size: 15664115 timestamp: 1772730794934 - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.13-ha9537fe_0_cpython.conda @@ -1932,6 +2074,7 @@ packages: constrains: - python_abi 3.12.* *_cp312 license: Python-2.0 + purls: [] size: 13672169 timestamp: 1772730464626 - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.13-h3d5d122_100_cp313.conda @@ -1954,6 +2097,7 @@ packages: - tk >=8.6.13,<8.7.0a0 - tzdata license: Python-2.0 + purls: [] size: 17650454 timestamp: 1775616128232 python_site_packages_path: lib/python3.13/site-packages @@ -1965,6 +2109,7 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL + purls: [] size: 317819 timestamp: 1765813692798 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda @@ -1985,6 +2130,8 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=hash-mapping size: 15513987 timestamp: 1779875850168 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda @@ -2005,6 +2152,8 @@ packages: - python_abi 3.12.* *_cp312 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=hash-mapping size: 15137152 timestamp: 1779876260804 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda @@ -2025,6 +2174,8 @@ packages: - python_abi 3.13.* *_cp313 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 15365931 timestamp: 1779875663184 - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda @@ -2035,6 +2186,7 @@ packages: - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD + purls: [] size: 3282953 timestamp: 1769460532442 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda @@ -2045,6 +2197,7 @@ packages: - llvm-openmp >=9.0.1 license: BSD-3-Clause license_family: BSD + purls: [] size: 8325 timestamp: 1764092507920 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/bzip2-1.0.8-hd037594_9.conda @@ -2054,6 +2207,7 @@ packages: - __osx >=11.0 license: bzip2-1.0.6 license_family: BSD + purls: [] size: 124834 timestamp: 1771350416561 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py311hc290fe0_0.conda @@ -2067,6 +2221,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 397978 timestamp: 1779838426505 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py312h04c11ed_0.conda @@ -2080,6 +2236,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 388500 timestamp: 1779838256904 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/coverage-7.14.1-py313h65a2061_0.conda @@ -2093,6 +2251,8 @@ packages: - tomli license: Apache-2.0 license_family: APACHE + purls: + - pkg:pypi/coverage?source=hash-mapping size: 396380 timestamp: 1779838267496 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/icu-78.3-hef89b57_0.conda @@ -2102,6 +2262,7 @@ packages: - __osx >=11.0 license: MIT license_family: MIT + purls: [] size: 12361647 timestamp: 1773822915649 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libblas-3.11.0-8_h51639a9_openblas.conda @@ -2119,6 +2280,7 @@ packages: - mkl <2027 license: BSD-3-Clause license_family: BSD + purls: [] size: 18949 timestamp: 1779859141315 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcblas-3.11.0-8_hb0561ab_openblas.conda @@ -2133,6 +2295,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18911 timestamp: 1779859147634 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libcxx-22.1.7-h55c6f16_0.conda @@ -2142,6 +2305,7 @@ packages: - __osx >=11.0 license: Apache-2.0 WITH LLVM-exception license_family: Apache + purls: [] size: 568252 timestamp: 1780441702930 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libexpat-2.8.1-hf6b4638_0.conda @@ -2153,6 +2317,7 @@ packages: - expat 2.8.1.* license: MIT license_family: MIT + purls: [] size: 69110 timestamp: 1779278728511 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libffi-3.5.2-hcf2aa1b_0.conda @@ -2162,6 +2327,7 @@ packages: - __osx >=11.0 license: MIT license_family: MIT + purls: [] size: 40979 timestamp: 1769456747661 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgcc-15.2.0-hcbb3090_19.conda @@ -2174,6 +2340,7 @@ packages: - libgomp 15.2.0 19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 404080 timestamp: 1778273064154 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran-15.2.0-h07b0088_19.conda @@ -2185,6 +2352,7 @@ packages: - libgfortran-ng ==15.2.0=*_19 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 139675 timestamp: 1778273280875 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libgfortran5-15.2.0-hdae7583_19.conda @@ -2196,6 +2364,7 @@ packages: - libgfortran 15.2.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL + purls: [] size: 599691 timestamp: 1778273075448 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblapack-3.11.0-8_hd9741b5_openblas.conda @@ -2210,6 +2379,7 @@ packages: - liblapacke 3.11.0 8*_openblas license: BSD-3-Clause license_family: BSD + purls: [] size: 18925 timestamp: 1779859153970 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/liblzma-5.8.3-h8088a28_0.conda @@ -2220,6 +2390,7 @@ packages: constrains: - xz 5.8.3.* license: 0BSD + purls: [] size: 92472 timestamp: 1775825802659 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libmpdec-4.0.0-h84a0fba_1.conda @@ -2229,6 +2400,7 @@ packages: - __osx >=11.0 license: BSD-2-Clause license_family: BSD + purls: [] size: 73690 timestamp: 1769482560514 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libopenblas-0.3.33-openmp_he657e61_0.conda @@ -2243,6 +2415,7 @@ packages: - openblas >=0.3.33,<0.3.34.0a0 license: BSD-3-Clause license_family: BSD + purls: [] size: 4304965 timestamp: 1776995497368 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libsqlite-3.53.2-h1ae2325_0.conda @@ -2253,6 +2426,7 @@ packages: - icu >=78.3,<79.0a0 - libzlib >=1.3.2,<2.0a0 license: blessing + purls: [] size: 927724 timestamp: 1780575223548 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/libzlib-1.3.2-h8088a28_2.conda @@ -2264,6 +2438,7 @@ packages: - zlib 1.3.2 *_2 license: Zlib license_family: Other + purls: [] size: 47759 timestamp: 1774072956767 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/llvm-openmp-22.1.7-hc7d1edf_0.conda @@ -2276,6 +2451,7 @@ packages: - intel-openmp <0.0a0 license: Apache-2.0 WITH LLVM-exception license_family: APACHE + purls: [] size: 285162 timestamp: 1780455637760 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ncurses-6.6-h1d4f5a5_0.conda @@ -2284,6 +2460,7 @@ packages: depends: - __osx >=11.0 license: X11 AND BSD-3-Clause + purls: [] size: 805509 timestamp: 1777423252320 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py311hbd1492f_0.conda @@ -2301,6 +2478,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping size: 7456206 timestamp: 1779169211856 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py312ha003a3f_0.conda @@ -2318,6 +2497,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping size: 6843172 timestamp: 1779169213435 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/numpy-2.4.6-py313hce9b930_0.conda @@ -2335,6 +2516,8 @@ packages: - numpy-base <0a0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/numpy?source=hash-mapping size: 6928597 timestamp: 1779169217159 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/openssl-3.6.2-hd24854e_0.conda @@ -2345,6 +2528,7 @@ packages: - ca-certificates license: Apache-2.0 license_family: Apache + purls: [] size: 3106008 timestamp: 1775587972483 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda @@ -2400,6 +2584,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14329411 timestamp: 1778602822615 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py312h6510ced_0.conda @@ -2455,6 +2641,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 13926263 timestamp: 1778602825408 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py313h1188861_0.conda @@ -2510,6 +2698,8 @@ packages: - zstandard >=0.23.0 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/pandas?source=hash-mapping size: 14056402 timestamp: 1778602842319 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.15-h8561d8f_0_cpython.conda @@ -2531,6 +2721,7 @@ packages: constrains: - python_abi 3.11.* *_cp311 license: Python-2.0 + purls: [] size: 14753109 timestamp: 1772730203101 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.13-h8561d8f_0_cpython.conda @@ -2552,6 +2743,7 @@ packages: constrains: - python_abi 3.12.* *_cp312 license: Python-2.0 + purls: [] size: 12127424 timestamp: 1772730755512 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda @@ -2574,6 +2766,7 @@ packages: - tk >=8.6.13,<8.7.0a0 - tzdata license: Python-2.0 + purls: [] size: 12966447 timestamp: 1775615694085 python_site_packages_path: lib/python3.13/site-packages @@ -2585,6 +2778,7 @@ packages: - ncurses >=6.5,<7.0a0 license: GPL-3.0-only license_family: GPL + purls: [] size: 313930 timestamp: 1765813902568 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda @@ -2605,6 +2799,8 @@ packages: - python_abi 3.11.* *_cp311 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 13954661 timestamp: 1779874558902 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda @@ -2625,6 +2821,8 @@ packages: - python_abi 3.12.* *_cp312 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 13936510 timestamp: 1779874824714 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda @@ -2645,6 +2843,8 @@ packages: - python_abi 3.13.* *_cp313 license: BSD-3-Clause license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping size: 14049103 timestamp: 1779874780525 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda @@ -2655,5 +2855,15 @@ packages: - libzlib >=1.3.1,<2.0a0 license: TCL license_family: BSD + purls: [] size: 3127137 timestamp: 1769460817696 +- pypi: . + name: pybeh-pd + requires_dist: + - numpy>=1.24 + - pandas>=2.0 + - scipy>=1.10 + - pytest>=7 ; extra == 'test' + - pytest-cov ; extra == 'test' + requires_python: '>=3.11,<3.14' diff --git a/pixi.toml b/pixi.toml index 6ebb640..1a394a3 100644 --- a/pixi.toml +++ b/pixi.toml @@ -10,6 +10,11 @@ numpy = ">=1.24" pandas = ">=2.0" scipy = ">=1.10" +# Editable install of this package (src/ layout) so `import pybeh_pd` resolves the +# real install path in every environment, not just via sys.path. +[pypi-dependencies] +pybeh_pd = { path = ".", editable = true } + [feature.test.dependencies] pytest = ">=7" pytest-cov = "*" @@ -28,8 +33,8 @@ py312 = ["py312", "test"] py313 = ["py313", "test"] [tasks] -# Pure-Python package: no compiled extensions to build. This task is the -# stand-in for "build" and just confirms the modules import. -build = "python -c \"import pybeh_pd; print('pybeh_pd import OK')\"" +# Pure-Python package: no compiled extensions to build. This confirms the +# editable install resolves and the package imports. +build = "python -c \"import pybeh_pd; print('pybeh_pd OK at', pybeh_pd.__file__)\"" test = "pytest -q" test-cov = "pytest -q --cov=pybeh_pd --cov=pybeh_copy --cov-report=term-missing" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d959825 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,49 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "pybeh_pd" +version = "0.1.0" +description = "Pandas-friendly wrappers around pybeh for free-recall behavioral analysis and plotting" +readme = "README.md" +requires-python = ">=3.11,<3.14" +license = { text = "MIT" } +authors = [{ name = "Computational Memory Lab (pennmem)" }] +keywords = ["free recall", "memory", "psychology", "pybeh", "lag-CRP", "pandas"] +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", + "Operating System :: OS Independent", +] +dependencies = [ + "numpy>=1.24", + "pandas>=2.0", + "scipy>=1.10", +] + +[project.optional-dependencies] +test = ["pytest>=7", "pytest-cov"] + +[project.urls] +Homepage = "https://github.com/pennmem/pybeh_pd" +Repository = "https://github.com/pennmem/pybeh_pd" + +[tool.hatch.build.targets.wheel] +packages = ["src/pybeh_pd"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +markers = [ + "hand_coded: concrete input -> hand-verified expected output", + "property: mathematical property (bounds, symmetry, identity, consistency)", + "edge_case: inputs that could silently invalidate results", + "consistency: cross-function / large-sample agreement", + "regression: golden-master behavior lock", + "integration: end-to-end pipeline on synthetic or real data", + "pins_bug: pins CURRENT (known-buggy) behavior; see bug_report.md", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 304f129..0000000 --- a/pytest.ini +++ /dev/null @@ -1,10 +0,0 @@ -[pytest] -testpaths = tests -markers = - hand_coded: concrete input -> hand-verified expected output - property: mathematical property (bounds, symmetry, identity, consistency) - edge_case: inputs that could silently invalidate results - consistency: cross-function / large-sample agreement - regression: golden-master behavior lock - integration: end-to-end pipeline on synthetic or real data - pins_bug: pins CURRENT (known-buggy) behavior; see bug_report.md diff --git a/src/pybeh_pd/__init__.py b/src/pybeh_pd/__init__.py new file mode 100644 index 0000000..68420fe --- /dev/null +++ b/src/pybeh_pd/__init__.py @@ -0,0 +1,15 @@ +"""pybeh_pd — pandas-friendly wrappers around pybeh for free-recall analysis. + +The public API is unchanged from the original single-file module: ``import +pybeh_pd as pb`` then call ``pb.pd_crp`` / ``pb.pd_temp_fact`` / ``pb.cousineau`` +etc. The implementation now lives in two internal modules: + +- ``_core`` — the analysis functions and pandas wrappers (formerly pybeh_pd.py). +- ``_pybeh`` — a vendored subset of pybeh (formerly pybeh_copy.py) so no external + pybeh install is required. + +Everything public from ``_core`` (which itself re-exports the vendored ``crp``, +``temp_fact``, ``make_clean_recalls_mask2d``, ``dist_percentile_rank``, +``temp_percentile_rank``) is re-exported here, preserving the original surface. +""" +from ._core import * # noqa: F401,F403 diff --git a/pybeh_pd.py b/src/pybeh_pd/_core.py similarity index 99% rename from pybeh_pd.py rename to src/pybeh_pd/_core.py index 28428aa..146b30f 100644 --- a/pybeh_pd.py +++ b/src/pybeh_pd/_core.py @@ -11,7 +11,7 @@ # from pybeh.temp_fact import temp_fact # from pybeh.dist_fact import dist_fact, dist_percentile_rank # from pybeh.mask_maker import make_clean_recalls_mask2d -from pybeh_copy import crp, temp_fact, make_clean_recalls_mask2d, dist_percentile_rank, temp_percentile_rank +from ._pybeh import crp, temp_fact, make_clean_recalls_mask2d, dist_percentile_rank, temp_percentile_rank def get_itemno_matrices(evs, itemno_column='itemno', list_index=['subject', 'session', 'list']): """Expects as input a dataframe (df) for one subject""" diff --git a/pybeh_copy.py b/src/pybeh_pd/_pybeh.py similarity index 100% rename from pybeh_copy.py rename to src/pybeh_pd/_pybeh.py diff --git a/tests/data/_regenerate_ltpfr2.py b/tests/data/_regenerate_ltpfr2.py index 56997b1..c144254 100644 --- a/tests/data/_regenerate_ltpfr2.py +++ b/tests/data/_regenerate_ltpfr2.py @@ -23,8 +23,8 @@ import cmlreaders as cml HERE = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(HERE, "..", "..")) # repo root (pybeh_pd) -sys.path.insert(0, os.path.join(HERE, "..")) # tests/ (real_data) +sys.path.insert(0, os.path.join(HERE, "..", "..", "src")) # src/ (pybeh_pd pkg) +sys.path.insert(0, os.path.join(HERE, "..")) # tests/ (real_data) from real_data import capture_outputs # noqa: E402 SUBJECT, N_SESSIONS, ITEMNO = "LTP093", 5, "item_num" diff --git a/tests/regression/cases.py b/tests/regression/cases.py index 7aed6e7..1d1149b 100644 --- a/tests/regression/cases.py +++ b/tests/regression/cases.py @@ -18,8 +18,8 @@ import numpy as np _HERE = os.path.dirname(__file__) -sys.path.insert(0, os.path.join(_HERE, "..")) # tests/ (factories) -sys.path.insert(0, os.path.join(_HERE, "..", "..")) # repo root (pybeh_pd) +sys.path.insert(0, os.path.join(_HERE, "..")) # tests/ (factories) +sys.path.insert(0, os.path.join(_HERE, "..", "..", "src")) # src/ (pybeh_pd pkg) import pybeh_pd as pb # noqa: E402 from factories import make_experiment # noqa: E402 diff --git a/tests/regression/test_regression.py b/tests/regression/test_regression.py index f35cf19..2aa7c9d 100644 --- a/tests/regression/test_regression.py +++ b/tests/regression/test_regression.py @@ -60,8 +60,6 @@ def test_regression(name, golden, live): def test_pd_min_temp_fact_default_raises(): """B4: default max_n_reps=1 path raises IndexError (broken).""" - import sys - sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) import pybeh_pd as pb from factories import make_experiment df = make_experiment(seed=0)["events"] @@ -71,8 +69,6 @@ def test_pd_min_temp_fact_default_raises(): def test_loftus_masson_unequal_kahana_raises(): """B1: function references undefined global `mat` -> NameError.""" - import sys - sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..")) import pybeh_pd as pb with pytest.raises(NameError): pb.loftus_masson_unequal_variance_kahana(np.ones((4, 3))) diff --git a/tests/test_clustering.py b/tests/test_clustering.py index f86b997..fd815b6 100644 --- a/tests/test_clustering.py +++ b/tests/test_clustering.py @@ -22,24 +22,17 @@ from __future__ import annotations import os -import sys import warnings -# Make the top-level ``pybeh_pd.py`` module win over the same-named source -# directory (a namespace-package shadow exists because the repo dir is itself -# called ``pybeh_pd``). Inserting the repo root first mirrors the regression -# harness (tests/regression/cases.py) and resolves to the real module file. -_HERE = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, os.path.join(_HERE, "..")) # repo root (contains pybeh_pd.py) +import numpy as np +import pytest -import numpy as np # noqa: E402 -import pytest # noqa: E402 +import pybeh_pd as pb +from factories import make_experiment -import pybeh_pd as pb # noqa: E402 -from factories import make_experiment # noqa: E402 - -# The module must be the real file, not the namespace-package shadow. -assert pb.__file__ is not None and pb.__file__.endswith("pybeh_pd.py"), pb.__file__ +# The package resolves to the src/ layout (conftest puts src/ on the path). +assert pb.__file__ is not None and pb.__file__.endswith( + os.path.join("pybeh_pd", "__init__.py")), pb.__file__ # Several pandas wrappers emit SettingWithCopyWarning / FutureWarning that are From 084ffa0bb376f6a69c45eed39fee77df8080893d Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 02:20:03 +0000 Subject: [PATCH 11/15] chore: move example notebooks and LoftusMasson.m into examples/ Relocate the 5 demo notebooks and the MATLAB Loftus-Masson reference out of the repo root into examples/ (excluded from the wheel). Notebook API updates are handled in the documentation phase. --- FR1_analyses.ipynb => examples/FR1_analyses.ipynb | 0 LoftusMasson.m => examples/LoftusMasson.m | 0 catFR1_analyses.ipynb => examples/catFR1_analyses.ipynb | 0 .../loftus_masson_example.ipynb | 0 psifr_test.ipynb => examples/psifr_test.ipynb | 0 repFR1_analyses.ipynb => examples/repFR1_analyses.ipynb | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename FR1_analyses.ipynb => examples/FR1_analyses.ipynb (100%) rename LoftusMasson.m => examples/LoftusMasson.m (100%) rename catFR1_analyses.ipynb => examples/catFR1_analyses.ipynb (100%) rename loftus_masson_example.ipynb => examples/loftus_masson_example.ipynb (100%) rename psifr_test.ipynb => examples/psifr_test.ipynb (100%) rename repFR1_analyses.ipynb => examples/repFR1_analyses.ipynb (100%) diff --git a/FR1_analyses.ipynb b/examples/FR1_analyses.ipynb similarity index 100% rename from FR1_analyses.ipynb rename to examples/FR1_analyses.ipynb diff --git a/LoftusMasson.m b/examples/LoftusMasson.m similarity index 100% rename from LoftusMasson.m rename to examples/LoftusMasson.m diff --git a/catFR1_analyses.ipynb b/examples/catFR1_analyses.ipynb similarity index 100% rename from catFR1_analyses.ipynb rename to examples/catFR1_analyses.ipynb diff --git a/loftus_masson_example.ipynb b/examples/loftus_masson_example.ipynb similarity index 100% rename from loftus_masson_example.ipynb rename to examples/loftus_masson_example.ipynb diff --git a/psifr_test.ipynb b/examples/psifr_test.ipynb similarity index 100% rename from psifr_test.ipynb rename to examples/psifr_test.ipynb diff --git a/repFR1_analyses.ipynb b/examples/repFR1_analyses.ipynb similarity index 100% rename from repFR1_analyses.ipynb rename to examples/repFR1_analyses.ipynb From 99839d00dbdbc1fbe5d012664cbe31076b4fbdd5 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 02:23:48 +0000 Subject: [PATCH 12/15] ci: add GitHub Actions test + build matrix Test job across Python 3.11-3.13 x numpy 1/2 (numpy 1 excluded on 3.13 where it has no wheels), running the full suite incl. the committed ltpFR2 real-data tests (no cmlreaders needed). Build job builds wheel+sdist via PEP 517 and smoke-installs the wheel. Validated locally: numpy 1.24/pandas 2.3, numpy 1.26/pandas 3.0, and numpy 2.4/pandas 3.0 all pass 216 tests. --- .github/workflows/test.yml | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..d5dfc8c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,69 @@ +name: tests + +on: + push: + branches: [main, modernize-package] + pull_request: + workflow_dispatch: + +jobs: + test: + name: py${{ matrix.python-version }} / numpy${{ matrix.numpy }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # pybeh_pd is pure-Python and supports both numpy majors. numpy 1.x has + # no wheels for Python 3.13, so that cell is excluded. + python-version: ["3.11", "3.12", "3.13"] + numpy: ["1", "2"] + exclude: + - python-version: "3.13" + numpy: "1" + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install package + test deps + run: | + python -m pip install --upgrade pip + python -m pip install -e ".[test]" + + - name: Pin numpy major + run: | + if [ "${{ matrix.numpy }}" = "1" ]; then + python -m pip install "numpy<2" + else + python -m pip install "numpy>=2" + fi + + - name: Show resolved versions + run: python -c "import numpy, pandas, scipy; print('numpy', numpy.__version__, '| pandas', pandas.__version__, '| scipy', scipy.__version__)" + + - name: Run test suite + run: pytest -q --cov=pybeh_pd --cov-report=term-missing + + build: + name: build wheel + sdist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Build distributions + run: | + python -m pip install --upgrade pip build + python -m build + - name: Smoke-install the wheel and import + run: | + python -m pip install dist/*.whl + python -c "import pybeh_pd as pb; print('OK', len([n for n in dir(pb) if not n.startswith('_')]), 'public names')" + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/* From 267fc824cd5b7af8fdc1b91f200d2f3fdf1c9f72 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 03:33:50 +0000 Subject: [PATCH 13/15] refactor: add pyright type annotations and pyflakes cleanup (Phase 9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Annotate all functions across _core.py and _pybeh.py to pyright 0 errors/0 warnings (basic mode, pyrightconfig.json scoped to the package). Remove pyflakes-flagged dead imports (scipy.spatial.distance) and unused locals (n_items in make_recalls_matrix, possibles_range/with_repeats in min_temp_fact, M_C in loftus_masson_analytic). The two undefined-name findings (mat, warnings) ARE bugs B1/B2 — left unfixed, suppressed with type-ignore + noqa citing the bug IDs so they stay tracked. 'types' kept with noqa (it is used via df.query @types, a pyflakes false positive). Adds ruff (F rules) to the pixi env + a CI lint job; pyright/ruff ratchet wired into the pre-commit hook. Behavior-neutral: 216 tests pass on numpy 1 and 2. --- .github/workflows/test.yml | 17 +++++++++ pixi.lock | 58 ++++++++++++++++++++++++++++ pixi.toml | 1 + pyproject.toml | 8 ++++ pyrightconfig.json | 7 ++++ src/pybeh_pd/_core.py | 78 ++++++++++++++++++-------------------- src/pybeh_pd/_pybeh.py | 33 +++++++++++++--- 7 files changed, 155 insertions(+), 47 deletions(-) create mode 100644 pyrightconfig.json diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d5dfc8c..4fb4d23 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -47,6 +47,23 @@ jobs: - name: Run test suite run: pytest -q --cov=pybeh_pd --cov-report=term-missing + lint: + name: pyright + ruff (pyflakes) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Install package + lint tools + run: | + python -m pip install --upgrade pip + python -m pip install -e . pyright ruff + - name: pyright (0 errors required) + run: pyright --project . + - name: ruff pyflakes (F) + run: ruff check --select F src/pybeh_pd + build: name: build wheel + sdist runs-on: ubuntu-latest diff --git a/pixi.lock b/pixi.lock index e659a3f..e7a2401 100644 --- a/pixi.lock +++ b/pixi.lock @@ -37,6 +37,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py313hbfd7664_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.16-h6a952e8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -97,6 +98,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py313hfd25234_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.13-h3d5d122_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.15.16-h1ddadc8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda - pypi: . @@ -141,6 +143,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py313h1188861_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.15.16-h80928e0_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - pypi: . @@ -179,6 +182,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py311h8032f78_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.16-h6a952e8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -238,6 +242,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py311h2a74ac8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.11.15-ha9537fe_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.15.16-h1ddadc8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda - pypi: . @@ -281,6 +286,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py311h8948835_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.11.15-h8561d8f_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.15.16-h80928e0_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - pypi: . @@ -319,6 +325,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py312h8ecdadd_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.12.13-hd63d673_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.16-h6a952e8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py312h54fa4ab_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -378,6 +385,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py312h8e27051_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.12.13-ha9537fe_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.15.16-h1ddadc8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py312h6309490_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda - pypi: . @@ -421,6 +429,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py312h6510ced_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.12.13-h8561d8f_0_cpython.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.15.16-h80928e0_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py312h4519d97_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - pypi: . @@ -457,6 +466,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/pandas-3.0.3-py313hbfd7664_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.13-h6add32d_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.16-h6a952e8_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py313h4b8bb8b_1.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda @@ -517,6 +527,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-64/pandas-3.0.3-py313hfd25234_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/python-3.13.13-h3d5d122_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/readline-8.3-h68b038d_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.15.16-h1ddadc8_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py313h9cbb6b6_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.13-h7142dee_3.conda - pypi: . @@ -561,6 +572,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/osx-arm64/pandas-3.0.3-py313h1188861_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/python-3.13.13-h20e6be0_100_cp313.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/readline-8.3-h46df422_0.conda + - conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.15.16-h80928e0_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py313h52f5312_1.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/tk-8.6.13-h010d191_3.conda - pypi: . @@ -1230,6 +1242,22 @@ packages: purls: [] size: 345073 timestamp: 1765813471974 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ruff-0.15.16-h6a952e8_0.conda + noarch: python + sha256: 8b0f50a439826eedfcd2741985aa55d8af7d281a4cebde7a8c2ceda6bbeb1bc4 + md5: 8d5840b229d9e957ac2af3c3b4e0eadc + depends: + - python + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + constrains: + - __glibc >=2.17 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff?source=compressed-mapping + size: 9192459 + timestamp: 1780611849620 - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_1.conda sha256: 3ae2ff1d1cc5930de2ca6ac03216118bdf13b2af6098e28e827f1ba25bfcbc4e md5: 089de2ee37e4e19885c985a4fe4aaf14 @@ -2112,6 +2140,21 @@ packages: purls: [] size: 317819 timestamp: 1765813692798 +- conda: https://conda.anaconda.org/conda-forge/osx-64/ruff-0.15.16-h1ddadc8_0.conda + noarch: python + sha256: 694b662dd988bda4168b54fe7313b9cc0378215d796e38d7f3e3b22a211e2e27 + md5: da82dbe7191b3de371645a43579bd427 + depends: + - python + - __osx >=11.0 + constrains: + - __osx >=10.13 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff?source=compressed-mapping + size: 9247784 + timestamp: 1780612065116 - conda: https://conda.anaconda.org/conda-forge/osx-64/scipy-1.17.1-py311h556693a_1.conda sha256: 4e68affca9e1d14cdb1fe6910c459ec4bd01b1217a867f7cfbf40830951f80aa md5: 972007d34efaf5755603391a91e7d50f @@ -2781,6 +2824,21 @@ packages: purls: [] size: 313930 timestamp: 1765813902568 +- conda: https://conda.anaconda.org/conda-forge/osx-arm64/ruff-0.15.16-h80928e0_0.conda + noarch: python + sha256: 6ce34bec1817caf6aa22c7ce28c4aeadd5fe02ea00d74425c498f4ec35276a1c + md5: 316cae3a5f921c633f8a6e1eb48604d8 + depends: + - python + - __osx >=11.0 + constrains: + - __osx >=11.0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/ruff?source=compressed-mapping + size: 8426033 + timestamp: 1780612122132 - conda: https://conda.anaconda.org/conda-forge/osx-arm64/scipy-1.17.1-py311h9a58382_1.conda sha256: b45f87414da242a9e40eb934e89513a856e6236d681611c2c9a21d074b03ef5a md5: 15f96f91b13cbefddbf998368d06adef diff --git a/pixi.toml b/pixi.toml index 1a394a3..db0ed57 100644 --- a/pixi.toml +++ b/pixi.toml @@ -18,6 +18,7 @@ pybeh_pd = { path = ".", editable = true } [feature.test.dependencies] pytest = ">=7" pytest-cov = "*" +ruff = "*" [feature.py311.dependencies] python = "3.11.*" diff --git a/pyproject.toml b/pyproject.toml index d959825..4dc49d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,6 +36,14 @@ Repository = "https://github.com/pennmem/pybeh_pd" [tool.hatch.build.targets.wheel] packages = ["src/pybeh_pd"] +[tool.ruff] +src = ["src"] + +[tool.ruff.lint] +# Scope to pyflakes (F) for the renovation: dead imports + unused locals, without +# imposing broader style churn on the legacy source. +select = ["F"] + [tool.pytest.ini_options] testpaths = ["tests"] markers = [ diff --git a/pyrightconfig.json b/pyrightconfig.json new file mode 100644 index 0000000..90be875 --- /dev/null +++ b/pyrightconfig.json @@ -0,0 +1,7 @@ +{ + "include": ["src/pybeh_pd"], + "pythonVersion": "3.11", + "typeCheckingMode": "basic", + "reportMissingImports": true, + "reportMissingModuleSource": false +} diff --git a/src/pybeh_pd/_core.py b/src/pybeh_pd/_core.py index 146b30f..fa4905c 100644 --- a/src/pybeh_pd/_core.py +++ b/src/pybeh_pd/_core.py @@ -1,9 +1,11 @@ +from __future__ import annotations +from typing import Optional, Any import pandas as pd import numpy as np import scipy as sp -from scipy import stats -from numpy import matlib -from scipy.spatial import distance, distance_matrix +from scipy import stats # noqa: F401 # loads scipy.stats submodule (used as sp.stats) + re-exported +from numpy import matlib # noqa: F401 # loads numpy.matlib submodule (used as np.matlib) + re-exported +from scipy.spatial import distance_matrix # from pybeh.make_recalls_matrix import make_recalls_matrix # from pybeh.crp import crp # from pybeh.spc import spc @@ -36,7 +38,7 @@ def get_itemno_matrices(evs, itemno_column='itemno', list_index=['subject', 'ses # d = {'prob': prob, 'serialpos': sps} # return pd.DataFrame(d, index=sps) -def make_recalls_matrix(pres_itemnos=None, rec_itemnos=None, max_n_reps=1): +def make_recalls_matrix(pres_itemnos: Optional[np.ndarray] = None, rec_itemnos: Optional[np.ndarray] = None, max_n_reps: int = 1) -> np.ndarray: ''' MAKE_RECALLS_MATRIX Make a standard recalls matrix. Given presented and recalled item numbers, finds the position of @@ -63,20 +65,19 @@ def make_recalls_matrix(pres_itemnos=None, rec_itemnos=None, max_n_reps=1): :param rec_itemnos: :return: ''' - n_trials = np.shape(pres_itemnos)[0] - n_items = np.shape(pres_itemnos)[1] - n_recalls = np.shape(rec_itemnos)[1] - + n_trials = np.shape(pres_itemnos)[0] # type: ignore[reportArgumentType] # None default is a required-arg sentinel + n_recalls = np.shape(rec_itemnos)[1] # type: ignore[reportArgumentType] # None default is a required-arg sentinel + recalls = np.zeros([n_trials, n_recalls, max_n_reps], dtype=int) for trial in np.arange(n_trials): for recall in np.arange(n_recalls): - if (rec_itemnos[trial, recall]) == 0 | (np.isnan(rec_itemnos[trial, recall])): + if (rec_itemnos[trial, recall]) == 0 | (np.isnan(rec_itemnos[trial, recall])): # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel continue - elif rec_itemnos[trial, recall] > 0: + elif rec_itemnos[trial, recall] > 0: # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel - serialpos = np.where(rec_itemnos[trial, recall] == pres_itemnos[trial,:])[0]+1 + serialpos = np.where(rec_itemnos[trial, recall] == pres_itemnos[trial,:])[0]+1 # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel if len(serialpos) > max_n_reps: raise Exception('An item was presented more than max_n_reps.') @@ -90,20 +91,20 @@ def make_recalls_matrix(pres_itemnos=None, rec_itemnos=None, max_n_reps=1): recalls = np.squeeze(recalls, axis=2) return recalls -def make_poss_recalls_matrix(pres_itemnos=None, max_n_reps=1): - n_trials = np.shape(pres_itemnos)[0] - n_items = np.shape(pres_itemnos)[1] - +def make_poss_recalls_matrix(pres_itemnos: Optional[np.ndarray] = None, max_n_reps: int = 1) -> np.ndarray: + n_trials = np.shape(pres_itemnos)[0] # type: ignore[reportArgumentType] # None default is a required-arg sentinel + n_items = np.shape(pres_itemnos)[1] # type: ignore[reportArgumentType] # None default is a required-arg sentinel + recalls = np.zeros([n_trials, n_items, max_n_reps], dtype=int) for trial in np.arange(n_trials): for item in np.arange(n_items): - if (pres_itemnos[trial, item]) == 0 | (np.isnan(pres_itemnos[trial, item])): + if (pres_itemnos[trial, item]) == 0 | (np.isnan(pres_itemnos[trial, item])): # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel continue - elif pres_itemnos[trial, item] > 0: + elif pres_itemnos[trial, item] > 0: # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel - serialpos = np.where(pres_itemnos[trial,item] == pres_itemnos[trial,:])[0]+1 + serialpos = np.where(pres_itemnos[trial,item] == pres_itemnos[trial,:])[0]+1 # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel if len(serialpos) > max_n_reps: raise Exception('An item was presented more than max_n_reps.') @@ -125,7 +126,7 @@ def get_min_trans(serialpos, rec): return pt[np.argmin(np.abs(pt))] def get_all_matrices(df, itemno_column='itemno', list_index=['subject', 'session', 'list'], pres_type="WORD", rec_type="REC_WORD", type_column='type', max_n_reps=1): - types = [pres_type, rec_type] + types = [pres_type, rec_type] # noqa: F841 # referenced in df.query via @types below #only include lists if both presentations and recalls are present (i.e. ntypes == 2) df = df.query(type_column + ' in @types') ntypes_df = df[list_index + [type_column]].groupby(list_index).agg({type_column: 'nunique'}).reset_index().rename(columns={type_column: 'ntypes'}) @@ -178,7 +179,7 @@ def pd_min_crp(df, lag_num=5, itemno_column='itemno', list_index=['subject', 'se 'lag': np.arange(-lag_num, (lag_num+1))} return pd.DataFrame(crp_dict, index=np.arange(-lag_num, (lag_num+1))) -def min_crp(recalls=None, poss_recalls=None, subjects=None, listLength=None, lag_num=None, skip_first_n=0): +def min_crp(recalls: Optional[np.ndarray] = None, poss_recalls: Optional[np.ndarray] = None, subjects: Any = None, listLength: Optional[int] = None, lag_num: Optional[int] = None, skip_first_n: int = 0) -> np.ndarray: ''' CRP Conditional response probability as a function of lag (lag-CRP). @@ -287,9 +288,9 @@ def min_crp(recalls=None, poss_recalls=None, subjects=None, listLength=None, lag next_rec = trial_recs[k + 1] next_rec = next_rec[next_rec != 0] if with_repeats: - pt = np.unique(np.array([get_min_trans(serialpos[serialpos != 0], rec) for serialpos in poss_recalls[j] if serialpos[0] not in seen], dtype=int))#don't increment more than once + pt = np.unique(np.array([get_min_trans(serialpos[serialpos != 0], rec) for serialpos in poss_recalls[j] if serialpos[0] not in seen], dtype=int))#don't increment more than once # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel else: - pt = np.unique(np.array([get_min_trans(serialpos[serialpos != 0], rec) for serialpos in poss_recalls[j] if serialpos not in seen], dtype=int))#don't increment more than once + pt = np.unique(np.array([get_min_trans(serialpos[serialpos != 0], rec) for serialpos in poss_recalls[j] if serialpos not in seen], dtype=int))#don't increment more than once # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel # for min lag-crp, we get the minimum possible distances poss[pt + listLength - 1] += 1 trans = get_min_trans(next_rec, rec) @@ -353,7 +354,7 @@ def pd_sem_crp(df, itemno_column='itemno', return pd.DataFrame(crp_dict).query('prob == prob') #remove bins with no data -def min_temp_fact(recalls=None, poss_recalls=None, subjects=None, listLength=None, skip_first_n=0): +def min_temp_fact(recalls: Optional[np.ndarray] = None, poss_recalls: Optional[np.ndarray] = None, subjects: Any = None, listLength: Optional[int] = None, skip_first_n: int = 0) -> np.ndarray: """ Returns the lag-based temporal clustering factor for each subject (Polyn, Norman, & Kahana, 2009). :param recalls: A trials x recalls matrix containing the serial positions (between 1 and listLength) of words @@ -385,20 +386,14 @@ def min_temp_fact(recalls=None, poss_recalls=None, subjects=None, listLength=Non recalls = np.array(recalls) subjects = np.array(subjects) - # Initialize range for possible next recalls, based on list length - possibles_range = range(1, listLength + 1) - # Initialize arrays to store each participant's results usub = np.unique(subjects) total = np.zeros_like(usub, dtype=float) count = np.zeros_like(usub, dtype=float) - + mask_recalls = recalls if mask_recalls.ndim == 3: - with_repeats = True mask_recalls = mask_recalls[:, :, 0] - else: - with_repeats = False # Identify locations of all correct recalls (not PLI, ELI, or repetition) clean_recalls_mask = np.array(make_clean_recalls_mask2d(mask_recalls)) @@ -417,7 +412,7 @@ def min_temp_fact(recalls=None, poss_recalls=None, subjects=None, listLength=Non # Identify possible transitions # possibles = np.array([abs(item - serialpos) for item in possibles_range if item not in seen]) possibles = abs(np.unique(np.array( - [get_min_trans(serialpos[serialpos != 0], rec) for serialpos in poss_recalls[i] if serialpos[0] not in seen], + [get_min_trans(serialpos[serialpos != 0], rec) for serialpos in poss_recalls[i] if serialpos[0] not in seen], # type: ignore[reportOptionalSubscript] # None default is a required-arg sentinel dtype=int)))#don't increment more than once # Identify actual transition # next_serialpos = trial_data[j + 1] @@ -501,7 +496,7 @@ def pd_dist_fact(df, rec_itemnos=None, itemno_column='itemno', skip_first_n=skip_first_n) return dist_fact_arr[0] -def sem_crp(recalls=None, recalls_itemnos=None, pres_itemnos=None, subjects=None, sem_sims=None, n_bins=10, bins=None, listLength=None, ret_counts=False): +def sem_crp(recalls: Optional[np.ndarray] = None, recalls_itemnos: Optional[np.ndarray] = None, pres_itemnos: Optional[np.ndarray] = None, subjects: Any = None, sem_sims: Any = None, n_bins: int = 10, bins: Any = None, listLength: Optional[int] = None, ret_counts: bool = False) -> tuple[Any, ...]: """bins should not include an upper bin""" if recalls_itemnos is None: raise Exception('You must pass a recalls-by-item-numbers matrix.') @@ -590,7 +585,7 @@ def sem_crp(recalls=None, recalls_itemnos=None, pres_itemnos=None, subjects=None else: return bin_means, crp -def dist_fact(rec_itemnos=None, pres_itemnos=None, subjects=None, dist_mat=None, is_similarity=False, skip_first_n=0, ret_counts=False): +def dist_fact(rec_itemnos: Optional[np.ndarray] = None, pres_itemnos: Optional[np.ndarray] = None, subjects: Any = None, dist_mat: Any = None, is_similarity: bool = False, skip_first_n: int = 0, ret_counts: bool = False): """ Returns a clustering factor score for each subject, based on the provided distance metric (Polyn, Norman, & Kahana, 2009). Can also be used with a similarity matrix (e.g. LSA, word2vec) if is_similarity is set to True. @@ -637,7 +632,7 @@ def dist_fact(rec_itemnos=None, pres_itemnos=None, subjects=None, dist_mat=None, # Provide a warning if the user inputs a dist_mat that looks like a similarity matrix (scores on diagonal are # large), but has left is_similarity as False if (not is_similarity) and np.nanmean(np.diagonal(dist_mat)) > np.nanmean(dist_mat): - warnings.warn('It looks like you might be using a similarity matrix (e.g. LSA, word2vec) instead of a distance' + warnings.warn('It looks like you might be using a similarity matrix (e.g. LSA, word2vec) instead of a distance' # type: ignore[reportUndefinedVariable] # noqa: F821 # bug B2 (missing import), see bug_report.md ' matrix, but you currently have is_similarity set to False. If you are using a similarity' ' matrix, make sure to set is_similarity to True when running dist_fact().') @@ -678,7 +673,7 @@ def dist_fact(rec_itemnos=None, pres_itemnos=None, subjects=None, dist_mat=None, return final_data, total, count return final_data -def pd_sem_crp_list(df, sim_columns=None, bins=None, pres_type="WORD", +def pd_sem_crp_list(df, sim_columns=None, bins: Any = None, pres_type="WORD", rec_type="REC_WORD", type_column='type', serialpos_col='serialpos', ret_counts=False, p=2): """Expects as input a dataframe (df) for one list. Doesn't require separate word_vals, expects them to be next to item. @@ -782,7 +777,6 @@ def loftus_masson_analytic(df_long, sub_col, cond_col, value_col): df_a['M'] = df_a[value_col].mean() df_a['M_S'] = df_a.groupby([sub_col])[value_col].transform('mean') df_a['M_C'] = df_a.groupby([cond_col])[value_col].transform('mean') - M_C = df_a.groupby([cond_col]).agg({value_col: 'mean'})[value_col].values #appendix A df_a['S_W'] = ((df_a[value_col] + df_a['M'] - df_a['M_S'] - df_a['M_C']) ** 2) @@ -790,13 +784,13 @@ def loftus_masson_analytic(df_long, sub_col, cond_col, value_col): df = (n_subs - 1) * (n_conds - 1) MS_SxC = SS_W / df SE = np.sqrt(MS_SxC / n_subs) - CI_equal = SE * sp.stats.t.ppf(0.975, df) # Eq. 2, pg. 482 + CI_equal = SE * sp.stats.t.ppf(0.975, df) # Eq. 2, pg. 482 # type: ignore[reportAttributeAccessIssue] # sp.stats imported via `from scipy import stats` #Unequal variances df_MS = df_a.groupby([cond_col, 'M_C'], as_index=False).agg({'S_W': 'sum'}) df_MS['MS_W'] = df_MS['S_W'] / (n_subs - 1) df_MS['estimator'] = (n_conds / (n_conds - 1)) * (df_MS['MS_W'] - (MS_SxC / (n_conds))) - df_MS['CI_unequal'] = np.sqrt(df_MS['estimator'] / n_subs) * sp.stats.t.ppf(0.975, (n_subs-1)) + df_MS['CI_unequal'] = np.sqrt(df_MS['estimator'] / n_subs) * sp.stats.t.ppf(0.975, (n_subs-1)) # type: ignore[reportAttributeAccessIssue] # sp.stats imported via `from scipy import stats` df_MS['CI_equal'] = CI_equal return df_MS[[cond_col, 'M_C', 'CI_unequal', 'CI_equal']] @@ -842,18 +836,18 @@ def loftus_masson_equal_variance_kahana(dat): SSint = SS_T - SSrow - SScol df_int = (numRows * numCols - 1) - (numRows - 1) - (numCols - 1) MSint = SSint / df_int - criterion = sp.stats.t.ppf(0.975, df_int) + criterion = sp.stats.t.ppf(0.975, df_int) # type: ignore[reportAttributeAccessIssue] # sp.stats imported via `from scipy import stats` # implementation of Loftus-Masson (1994), equation (2) CI = np.sqrt(MSint / numRows) * criterion * np.ones(numCols) return CI def loftus_masson_unequal_variance_kahana(dat): - dat = mat + dat = mat # type: ignore[reportUndefinedVariable] # noqa: F821 # bug B1 (undefined `mat`), see bug_report.md # normalize the data grandMean = np.nanmean(dat) subjMean = np.nanmean(dat, axis=1) - subjMean = np.matlib.repmat(subjMean, dat.shape[1], 1).T + subjMean = np.matlib.repmat(subjMean, dat.shape[1], 1).T # type: ignore[reportAttributeAccessIssue] # np.matlib imported via `from numpy import matlib` dat = dat - (subjMean - grandMean) # compute sums @@ -882,5 +876,5 @@ def loftus_masson_unequal_variance_kahana(dat): MS_w = (np.nansum(dat ** 2, axis=0) - ((Tc ** 2) / Nsubj)) / (Nsubj-1) # p.484 estimator = (NcondValid / (NcondValid - 1)) * (MS_w - (MS_SxC / NcondValid)) - CI = np.sqrt(estimator / Nsubj) * sp.stats.t.ppf(0.975, dat.shape[0] - 1) + CI = np.sqrt(estimator / Nsubj) * sp.stats.t.ppf(0.975, dat.shape[0] - 1) # type: ignore[reportAttributeAccessIssue] # sp.stats imported via `from scipy import stats` return Tc, CI \ No newline at end of file diff --git a/src/pybeh_pd/_pybeh.py b/src/pybeh_pd/_pybeh.py index eb00e51..3a5c27e 100644 --- a/src/pybeh_pd/_pybeh.py +++ b/src/pybeh_pd/_pybeh.py @@ -1,7 +1,12 @@ +from __future__ import annotations + +from typing import Any, Optional, Union + import numpy as np import copy -def make_clean_recalls_mask2d(data): + +def make_clean_recalls_mask2d(data: Any) -> Any: """makes a clean mask without repetition and intrusion""" result = copy.deepcopy(data) for num, item in enumerate(data): @@ -15,7 +20,13 @@ def make_clean_recalls_mask2d(data): result[num][index] = 0 return result -def crp(recalls=None, subjects=None, listLength=None, lag_num=None, skip_first_n=0): +def crp( + recalls: Optional[Any] = None, + subjects: Optional[Any] = None, + listLength: Optional[int] = None, + lag_num: Optional[int] = None, + skip_first_n: int = 0, +) -> np.ndarray: ''' CRP Conditional response probability as a function of lag (lag-CRP). @@ -120,7 +131,12 @@ def crp(recalls=None, subjects=None, listLength=None, lag_num=None, skip_first_n return result[:, listLength - lag_num - 1:listLength + lag_num] -def temp_fact(recalls=None, subjects=None, listLength=None, skip_first_n=0): +def temp_fact( + recalls: Optional[Any] = None, + subjects: Optional[Any] = None, + listLength: Optional[int] = None, + skip_first_n: int = 0, +) -> np.ndarray: """ Returns the lag-based temporal clustering factor for each subject (Polyn, Norman, & Kahana, 2009). :param recalls: A trials x recalls matrix containing the serial positions (between 1 and listLength) of words @@ -192,7 +208,10 @@ def temp_fact(recalls=None, subjects=None, listLength=None, skip_first_n=0): return final_data -def temp_percentile_rank(actual, possible): +def temp_percentile_rank( + actual: Union[int, float, np.number, Any], + possible: Any, +) -> Optional[Union[float, np.floating]]: """ Helper function to return the percentile rank of the actual transition within the list of possible transitions. :param actual: The distance of the actual transition that was made. @@ -220,7 +239,11 @@ def temp_percentile_rank(actual, possible): return ptile_rank -def dist_percentile_rank(actual, possible, is_similarity=False): +def dist_percentile_rank( + actual: Union[int, float, np.number, Any], + possible: Any, + is_similarity: bool = False, +) -> Optional[Union[float, np.floating]]: """ Helper function to return the percentile rank of the actual transition within the list of possible transitions. :param actual: The distance of the actual transition that was made. From a2c3fdf82b798568f6723baf5da725485974abcb Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 04:02:57 +0000 Subject: [PATCH 14/15] docs: rewrite README and add tested quickstart (Phase 11) Replace the stale 'just a module, append to sys.path' README with a full one: purpose, the utilities provided, pip/editable/git install paths, a quickstart that tests/test_readme.py executes (so it can't drift), dev/test instructions, and the CI summary. Strip the hardcoded sys.path.append lines from the example notebooks now that the package is pip-installable. Notebook data-gating, the pandas-3 groupby idiom, and the missing LICENSE file are flagged in documentation_report.md for human follow-up. 217 tests pass. --- README.md | 106 +++++++++++++++++++++++++-- examples/FR1_analyses.ipynb | 1 - examples/catFR1_analyses.ipynb | 1 - examples/loftus_masson_example.ipynb | 1 - examples/repFR1_analyses.ipynb | 1 - tests/test_readme.py | 37 ++++++++++ 6 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 tests/test_readme.py diff --git a/README.md b/README.md index 5c20a71..b684345 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,103 @@ # pybeh_pd - -A lightweight wrapper around pybeh for easy analysis and plotting of free recall data with pandas and seaborn. -See the attached notebooks for examples of how to use this module and psifr test for comparison to a related package. -It is just a module not yet a package so import by adding the path, i.e. +A lightweight, pure-Python wrapper around [pybeh](https://github.com/pennmem/pybeh) +for analyzing and plotting **free-recall** behavioral data with pandas and seaborn. +It re-expresses pybeh's matrix-based analyses as functions that take **tidy, +long-format pandas DataFrames** of presentation/recall events, and adds +within-subject confidence-interval helpers for plotting. + +A minimal subset of `pybeh` is vendored (`pybeh_pd._pybeh`), so **no separate +`pybeh` install is required**. + +## What it provides + +Given a long-format events DataFrame (one row per presented/recalled item), the +`pd_*` functions compute, per subject: + +- **`pd_crp`** — lag conditional response probability (lag-CRP; the temporal + contiguity effect). +- **`pd_temp_fact`** — temporal clustering factor (Polyn, Norman & Kahana, 2009). +- **`pd_sem_crp`** — semantic CRP, binned by a similarity space. +- **`pd_dist_fact`** — distance/similarity clustering factor. +- **`pd_min_crp` / `pd_min_temp_fact`** — repeated-presentation-aware variants. +- **`pd_sem_crp_list`, `pd_dist_fact_list`, and `*_sub`** — per-list / per-subject + aggregating variants. +- **CI helpers** for within-subject error bars: `cousineau` + (Cousineau–Morey–O'Brien), `loftus_masson_analytic`, and the Loftus–Masson + Kahana ports. + +The underlying matrix builders (`make_recalls_matrix`, `get_all_matrices`, ...) +and pybeh primitives (`crp`, `temp_fact`, ...) are also exposed. + +## Install + +Pure Python — install from source with pip: + +```bash +pip install . # from a clone +pip install git+https://github.com/pennmem/pybeh_pd.git # from GitHub +pip install -e . # editable (for development) ``` -import sys -sys.path.append('~/pybeh_pd') + +Requires Python 3.11–3.13 and numpy / pandas / scipy (installed automatically). + +## Quickstart + +```python +import pandas as pd import pybeh_pd as pb -``` \ No newline at end of file + +# One subject, two 4-item lists. WORD rows are presentations; REC_WORD rows are +# recalls. `itemno` is the item id; recalls reference the presented item numbers. +events = pd.DataFrame({ + "subject": "subj1", "session": 0, + "list": [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], + "type": ["WORD"] * 4 + ["REC_WORD"] * 3 + ["WORD"] * 4 + ["REC_WORD"] * 3, + "itemno": [11, 12, 13, 14, 12, 13, 14, 21, 22, 23, 24, 23, 22, 21], +}) + +# Expects one subject's events; group by subject for many-subject data: +# events.groupby("subject").apply(pb.pd_crp, itemno_column="itemno") +crp = pb.pd_crp(events, lag_num=3) +print(crp[["lag", "prob"]]) +# lag 0 is NaN; forward (+1) and backward (-1) adjacent transitions dominate. + +print("temporal clustering factor:", pb.pd_temp_fact(events)) +``` + +The default column names are `subject` / `session` / `list` (the trial index), +`type` (with `"WORD"` presentations and `"REC_WORD"` recalls), and `itemno`; all +are overridable via keyword arguments (e.g. `itemno_column="item_num"`). + +See [`examples/`](examples/) for notebooks demonstrating FR1, catFR1, repFR1, and +the Loftus–Masson confidence intervals on real datasets. + +## Development + +This repo uses [pixi](https://pixi.sh) for a reproducible dev environment: + +```bash +pixi run build # confirm the package imports +pixi run test # run the test suite +pixi run test-cov # with coverage +``` + +Or with plain pip/pytest: + +```bash +pip install -e ".[test]" +pytest +``` + +The test suite includes a golden-master **behavior-lock** regression suite, +per-function unit tests, and integration tests on a committed 5-session sample of +real ltpFR2 free-recall data (no external data access required). + +## Continuous integration + +GitHub Actions runs the suite across Python 3.11–3.13 and both numpy 1.x and 2.x +(pandas 2.x/3.x), plus a wheel/sdist build and a pyright + ruff lint job. + +## License + +MIT. diff --git a/examples/FR1_analyses.ipynb b/examples/FR1_analyses.ipynb index ec33ce4..849e9b7 100644 --- a/examples/FR1_analyses.ipynb +++ b/examples/FR1_analyses.ipynb @@ -13,7 +13,6 @@ "import seaborn as sns\n", "import pandas as pd\n", "import sys\n", - "sys.path.append('/home1/djhalp/pybeh_pd')\n", "import pybeh_pd as pb" ] }, diff --git a/examples/catFR1_analyses.ipynb b/examples/catFR1_analyses.ipynb index e6a6119..187fba5 100644 --- a/examples/catFR1_analyses.ipynb +++ b/examples/catFR1_analyses.ipynb @@ -13,7 +13,6 @@ "import seaborn as sns\n", "import pandas as pd\n", "import sys\n", - "sys.path.append('/home1/djhalp/pybeh_pd')\n", "import pybeh_pd as pb" ] }, diff --git a/examples/loftus_masson_example.ipynb b/examples/loftus_masson_example.ipynb index 6b5c6ca..d6a9cb1 100644 --- a/examples/loftus_masson_example.ipynb +++ b/examples/loftus_masson_example.ipynb @@ -12,7 +12,6 @@ "from scipy import stats\n", "import pandas as pd\n", "import sys\n", - "sys.path.append('/home1/djhalp/pybeh_pd')\n", "import pybeh_pd as pb\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" diff --git a/examples/repFR1_analyses.ipynb b/examples/repFR1_analyses.ipynb index af14ff0..b0fdc0f 100644 --- a/examples/repFR1_analyses.ipynb +++ b/examples/repFR1_analyses.ipynb @@ -24,7 +24,6 @@ "import seaborn as sns\n", "import pandas as pd\n", "import sys\n", - "sys.path.append('~/pybeh_pd')\n", "import pybeh_pd as pb\n", "import importlib\n", "importlib.reload(pb)" diff --git a/tests/test_readme.py b/tests/test_readme.py new file mode 100644 index 0000000..6aa0f44 --- /dev/null +++ b/tests/test_readme.py @@ -0,0 +1,37 @@ +"""Execute the README quickstart so documentation can't silently drift. + +Extracts the first ```python fenced block from README.md, runs it, and checks the +documented results (lag-0 CRP is NaN, the +/-1 lag-CRP values, the temporal +clustering factor). If the README example or the API changes incompatibly, this +test fails. +""" +from __future__ import annotations + +import os +import re + +import numpy as np + +README = os.path.join(os.path.dirname(__file__), "..", "README.md") + + +def _first_python_block(md_text: str) -> str: + m = re.search(r"```python\n(.*?)```", md_text, re.DOTALL) + assert m, "no ```python block found in README.md" + return m.group(1) + + +def test_readme_quickstart_runs(): + with open(README) as fh: + code = _first_python_block(fh.read()) + ns: dict = {} + exec(compile(code, "README.md", "exec"), ns) + + crp = ns["crp"].set_index("lag")["prob"] + assert np.isnan(crp.loc[0]) + assert np.isclose(crp.loc[1], 2 / 3) + assert np.isclose(crp.loc[-1], 2 / 3) + + import pybeh_pd as pb + tf = pb.pd_temp_fact(ns["events"]) + assert np.isclose(tf, 0.875) From 9b2e8d75fae3c75f47f517bbe7f9423e0e7555d0 Mon Sep 17 00:00:00 2001 From: Riley DeHaan Date: Wed, 10 Jun 2026 04:06:22 +0000 Subject: [PATCH 15/15] =?UTF-8?q?release:=20v0.1.0=20=E2=80=94=20single-so?= =?UTF-8?q?urced=20version,=20MIT=20LICENSE,=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add __version__ = 0.1.0 to the package, read dynamically by hatchling (pyproject version is now dynamic). Add an MIT LICENSE file and point pyproject license at it (+ MIT classifier). Add CHANGELOG.md documenting the modernization and the eight discovered-but-unfixed bugs (B1-B8) pinned for a later fix pass. import and dist metadata both report 0.1.0; 217 tests pass. --- CHANGELOG.md | 62 ++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 ++++++++++++++ pyproject.toml | 8 ++++-- src/pybeh_pd/__init__.py | 2 ++ 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 LICENSE diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1df36b1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,62 @@ +# Changelog + +All notable changes to `pybeh_pd` are documented here. This project adheres to +[Semantic Versioning](https://semver.org/). + +## 0.1.0 — 2026-06-10 + +First packaged release. The package was modernized from a single-file, +`sys.path.append`-style module into a clean, tested, pip-installable package +**without changing any observable analysis behavior** (a golden-master regression +suite locks the numerical output). + +### Packaging & build +- Converted to a `src/` layout package: `pybeh_pd/{__init__, _core, _pybeh}.py`. + The vendored pybeh subset (formerly `pybeh_copy.py`) is now the internal + `pybeh_pd._pybeh`, imported via a proper intra-package import (no more reliance + on the repo root being on `sys.path`). +- Added a `pyproject.toml` (hatchling backend); installable via + `pip install .` / `pip install -e .` / `pip install git+https://…`. Builds clean + wheel + sdist. +- Single-sourced `__version__` (read by hatchling). +- Added a `pixi.toml` reproducible dev environment (Python 3.11/3.12/3.13) with + `build` / `test` / `test-cov` tasks. +- Moved example notebooks and `LoftusMasson.m` into `examples/` (excluded from the + wheel); removed hardcoded `sys.path.append` lines from the notebooks. +- Added an MIT `LICENSE`. + +### Compatibility +- Supports Python 3.11–3.13 and both numpy 1.x and 2.x (pandas 2.x/3.x). Verified + green on numpy 1.24/1.26/2.4 across pandas 2.3/3.0. + +### Tests & CI +- Added a golden-master **behavior-lock** regression suite plus comprehensive + per-function unit tests (hand-coded values, mathematical properties, edge + cases) covering all public functions. +- Added real-data integration tests on a committed 5-session ltpFR2 sample (no + rhino/cmlreaders needed at test time), reproducing the temporal contiguity + effect and temporal clustering factor. +- Added GitHub Actions: test matrix (Python 3.11–3.13 × numpy 1/2), wheel/sdist + build, and a pyright + ruff lint job. + +### Code quality +- Added pyright type annotations across the package (0 errors / 0 warnings, + basic mode); added `pyrightconfig.json`. +- Removed pyflakes-flagged dead imports and unused locals (behavior-neutral). + +### Known bugs (discovered, NOT fixed in this release) +These were found during modernization and intentionally left unchanged so the +behavior baseline stays clean; they are pinned by tests and will be fixed in a +follow-up against the regression suite: +- **B1** `loftus_masson_unequal_variance_kahana` references an undefined `mat` + (raises on every call). +- **B2** `dist_fact` calls `warnings.warn` without importing `warnings`. +- **B3** `pd_dist_fact_list`'s `if count == np.nan` guard never fires. +- **B4** `pd_min_temp_fact` with the default `max_n_reps=1` raises `IndexError`. +- **B5** the percentile-rank helpers crash on a Python-scalar `actual` under + numpy 2. +- **B6** operator-precedence bug misclassifies NaN-padded recalls as intrusions + in `make_recalls_matrix` / `make_poss_recalls_matrix`. +- **B7** `cousineau` with a single condition raises `ZeroDivisionError`. +- **B8** the documented `groupby('subject').apply(pd_crp, …)` idiom breaks on + pandas 3 (the grouping column is dropped); use an explicit per-subject loop. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..353fac6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Computational Memory Lab, University of Pennsylvania + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pyproject.toml b/pyproject.toml index 4dc49d1..8986840 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,14 +4,15 @@ build-backend = "hatchling.build" [project] name = "pybeh_pd" -version = "0.1.0" +dynamic = ["version"] description = "Pandas-friendly wrappers around pybeh for free-recall behavioral analysis and plotting" readme = "README.md" requires-python = ">=3.11,<3.14" -license = { text = "MIT" } +license = { file = "LICENSE" } authors = [{ name = "Computational Memory Lab (pennmem)" }] keywords = ["free recall", "memory", "psychology", "pybeh", "lag-CRP", "pandas"] classifiers = [ + "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -33,6 +34,9 @@ test = ["pytest>=7", "pytest-cov"] Homepage = "https://github.com/pennmem/pybeh_pd" Repository = "https://github.com/pennmem/pybeh_pd" +[tool.hatch.version] +path = "src/pybeh_pd/__init__.py" + [tool.hatch.build.targets.wheel] packages = ["src/pybeh_pd"] diff --git a/src/pybeh_pd/__init__.py b/src/pybeh_pd/__init__.py index 68420fe..183f967 100644 --- a/src/pybeh_pd/__init__.py +++ b/src/pybeh_pd/__init__.py @@ -12,4 +12,6 @@ ``temp_fact``, ``make_clean_recalls_mask2d``, ``dist_percentile_rank``, ``temp_percentile_rank``) is re-exported here, preserving the original surface. """ +__version__ = "0.1.0" + from ._core import * # noqa: F401,F403